Skip to main content

Button

Buttons help users carry out important actions on a page like starting a survey or saving their answers.

<button type="submit" class="ons-btn">
  <span class="ons-btn__inner">Save and continue</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "text": "Save and continue"
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

When to use this component

Use a button to help direct users to perform a specific action. They should be used to start a process, save users information, and progress through a service.

How to use this component

Write button text in sentence case, describing the action it performs. The button label should be short, clear and direct. For example ‘Save and continue’ or ‘Sign in’.

Align the primary action button to the left edge of a form.

Primary (default)

Use a primary button for the main call to action on a page.

Avoid using multiple primary buttons on the same page because it will reduce the impact and make it hard for users to know what to do next.

<button type="submit" class="ons-btn">
  <span class="ons-btn__inner">Save and continue</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "text": "Save and continue"
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Variants

To use an alternative type of button, set the variants parameter to either a single value or an array of multiple values. For example, "variants": 'small' or "variants": ['small', 'secondary'].

Small

In certain circumstances there may be the need for multiple primary actions to exist on a page. The small primary button should be used in this scenario only when each action has the same context, for example, a list containing business surveys that a user needs to start.

<button type="button" class="ons-btn ons-btn--small">
  <span class="ons-btn__inner">Add</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "type": 'button',
        "text": 'Add',
        "variants": 'small'
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Secondary

Use secondary buttons in combination with a primary button for secondary actions on the page. Avoid using too many secondary buttons on the same page as it can make hard for users to know what to do next.

<button type="button" class="ons-btn ons-btn--secondary">
  <span class="ons-btn__inner">Add a person</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "type": 'button',
        "text": 'Add a person',
        "variants": 'secondary'
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Secondary (small)

A small secondary button should be used within the same context of a primary small button when there is an additional action available along with the primary action.

<button type="button" class="ons-btn ons-btn--secondary ons-btn--small">
  <span class="ons-btn__inner">Add</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "type": 'button',
        "text": 'Add',
        "variants": ['secondary', 'small']
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Call to action

The call to action button should be used when a link to a new page is the primary call to action on a page. For example, a “Start survey” button.

Links simply styled as buttons are not accessible to users who navigate a web page with voice commands. Setting the url parameter will create a link with role=button which will let these users select the button.

<a href="#0" role="button" class="ons-btn ons-btn--link ons-js-submit-btn">
  <span class="ons-btn__inner">Get started
    <svg class="ons-svg-icon ons-u-ml-xs" viewBox="0 0 8 13" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
      <path d="M5.74,14.28l-.57-.56a.5.5,0,0,1,0-.71h0l5-5-5-5a.5.5,0,0,1,0-.71h0l.57-.56a.5.5,0,0,1,.71,0h0l5.93,5.93a.5.5,0,0,1,0,.7L6.45,14.28a.5.5,0,0,1-.71,0Z" transform="translate(-5.02 -1.59)" />
    </svg>
  </span>
</a>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "type": 'button',
        "text": 'Get started',
        "url": '#0'
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Call to action opening in a new window

Use this button when a page needs to open in a new window, for example, for a web chat service.

Set the newWindow parameter to true. This adds a warning for screen reader users so they know a new window will open when they select the button. This helps them understand why the back button in the browser is disabled on the new page.

<a href="#0" role="button" class="ons-btn ons-btn--link ons-js-submit-btn" target="_blank" rel="noopener">
  <span class="ons-btn__inner">Web chat
    <svg class="ons-svg-icon ons-u-ml-xs" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
      <path d="M13.5,9H13a.5.5,0,0,0-.5.5v3h-9v-9h3A.5.5,0,0,0,7,3V2.5A.5.5,0,0,0,6.5,2h-4a.5.5,0,0,0-.5.5v11a.5.5,0,0,0,.5.5h11a.5.5,0,0,0,.5-.5v-4A.5.5,0,0,0,13.5,9Z" transform="translate(-2 -1.99)" />
      <path d="M8.83,7.88a.51.51,0,0,0,.71,0l2.31-2.32,1.28,1.28A.51.51,0,0,0,14,6.49v-4a.52.52,0,0,0-.5-.5h-4A.51.51,0,0,0,9,2.52a.58.58,0,0,0,.14.33l1.28,1.28L8.12,6.46a.51.51,0,0,0,0,.71Z" transform="translate(-2 -1.99)" />
    </svg>
  </span>
  <span class="ons-btn__new-window-description ons-u-vh">opens in a new window</span>
</a>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "type": 'button',
        "text": 'Web chat',
        "url": '#0',
        "newWindow": true
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Ghost

The ghosted button style is for use in the header or footer. This can be used to allow a user to exit or save and sign out of a service.

Setting the iconType parameter to exit adds an appropriate icon for a ‘sign out’ or ‘exit’ button.

<div style="padding: 1.5rem; background: #206095">
  <a href="#0" role="button" class="ons-btn ons-btn--ghost ons-btn--link ons-js-submit-btn">
    <span class="ons-btn__inner">Save and sign out
      <svg class="ons-svg-icon ons-u-ml-xs" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
        <path d="M13.85,7.65l-2.5-2.5a.5.5,0,0,0-.71,0,.48.48,0,0,0-.15.36V7h-3a.5.5,0,0,0-.5.5v1a.5.5,0,0,0,.5.5h3v1.5A.49.49,0,0,0,11,11a.48.48,0,0,0,.34-.14l2.51-2.5a.49.49,0,0,0,0-.68Z" transform="translate(-2 -2)" />
        <path d="M8.5,14h-6a.5.5,0,0,1-.5-.5V2.5A.5.5,0,0,1,2.5,2h6a.5.5,0,0,1,.5.5V3a.5.5,0,0,1-.5.5h-5v9h5A.5.5,0,0,1,9,13v.5A.5.5,0,0,1,8.5,14Z" transform="translate(-2 -2)" />
      </svg>
    </span>
  </a>
</div>
{% from "components/button/_macro.njk" import onsButton %}
<div style="padding: 1.5rem; background: #206095">
    {{
        onsButton({
            "type": 'button',
            "text": 'Save and sign out',
            "url": '#0',
            "variants": 'ghost',
            "iconType": "exit",
            "iconPosition": "after"
        })
    }}
</div>
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Disabled

Disabled buttons have poor contrast and can confuse some users. Only use disabled buttons if research shows it makes the page easier to understand. For example, the “Send message” button on the Send and reply to messages pattern is disabled until a message is entered into the field.

Use "variant": 'disabled' with the disabled=true attribute parameter for buttons that have no event/action but need to be displayed.

<button type="button" class="ons-btn ons-btn--disabled" disabled="true">
  <span class="ons-btn__inner">Submit</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "type": 'button',
        "text": 'Submit',
        "variants": 'disabled',
        "attributes": {
            "disabled": "true"
        }
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Loader

The loader button should be used when the button starts a process that can take longer than expected to complete.

Using it will prevent a form being submitted more than once if a user tries to select the button multiple times.

Setting "submitType": 'loader' will disable the button when selected and show an animated loading icon.

<form onsubmit="return false;">
  <button type="submit" class="ons-btn ons-btn--loader ons-js-loader ons-js-submit-btn">
    <span class="ons-btn__inner">Submit
      <svg class="ons-svg-icon ons-u-ml-xs" xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" fill="currentcolor">
        <rect x="0" y="0" width="100" height="100" fill="none"></rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(0 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(30 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.08333333333333333s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(60 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.16666666666666666s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(90 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.25s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(120 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.3333333333333333s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(150 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.4166666666666667s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(180 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.5s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(210 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.5833333333333334s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(240 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.6666666666666666s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(270 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.75s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(300 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.8333333333333334s' repeatCount='indefinite' />
        </rect>
        <rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(330 50 50) translate(0 -30)'>
          <animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.9166666666666666s' repeatCount='indefinite' />
        </rect>
      </svg>
    </span>
  </button>
</form>
{% from "components/button/_macro.njk" import onsButton %}
<form onsubmit="return false;">
    {{
        onsButton({
            "text": 'Submit',
            "submitType": "loader"
        })
    }}
</form>
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Timer

The timer button can be used to prevent forms being submitted twice when users double-click the submit button. Setting "submitType": 'loader' will disable the button for one second after it’s selected.

<form onsubmit="return false;">
  <button type="submit" class="ons-btn ons-js-timer ons-js-submit-btn">
    <span class="ons-btn__inner">Submit</span>
  </button>
</form>
{% from "components/button/_macro.njk" import onsButton %}
<form onsubmit="return false;">
    {{
        onsButton({
            "text": 'Submit',
            "submitType": "timer"
        })
    }}
</form>
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Print

Setting "buttonStyle": 'print' will show a button with a print icon and add classes used in the print-button.js file.

The button will not show until the JavaScript has run, and will not be shown on a printed page.

<button type="button" class="ons-btn ons-btn--small ons-btn--secondary ons-btn--print ons-u-d-no ons-js-print-btn">
  <span class="ons-btn__inner">
    <svg class="ons-svg-icon ons-u-mr-xs" viewBox="0 0 20 16" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
      <path d="M17 4H3C1.3 4 0 5.2 0 6.8v5.5h4V16h12v-3.7h4V6.8C20 5.2 18.7 4 17 4zm-3 10H6V9h8v5zm3-6a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-1-8H4v3h12V0z" />
    </svg>
    Print this page</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}

{{
    onsButton({
        "type": 'button',
        "text": 'Print this page',
        "buttonStyle": 'print',
        "variants": ['small', 'secondary']
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Download

Setting "buttonStyle": 'download' will show a button with a download icon and add the download attribute to make the browser save the file at the specified url.

<a href="#0" role="button" class="ons-btn ons-btn--small ons-btn--secondary ons-btn--link ons-js-submit-btn ons-btn--download" download>
  <span class="ons-btn__inner">
    <svg class="ons-svg-icon ons-u-mr-xs" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
      <path d="M5.6 9a.48.48 0 0 0 .7 0l3-3.2a.48.48 0 0 0 0-.7C9.3 5 9.2 5 9 5H7.5V.5A.47.47 0 0 0 7 0H5a.47.47 0 0 0-.5.5V5H3a.47.47 0 0 0-.5.5.37.37 0 0 0 .1.3Z" />
      <path d="M11.5 9H11a.47.47 0 0 0-.5.5v1h-9v-1A.47.47 0 0 0 1 9H.5a.47.47 0 0 0-.5.5v2a.47.47 0 0 0 .5.5h11a.47.47 0 0 0 .5-.5v-2a.47.47 0 0 0-.5-.5Z" />
    </svg>
    Save answers as PDF</span>
</a>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "buttonStyle": 'download',
        "text": 'Save answers as PDF',
        "url": '#0',
        "variants": ['small', 'secondary']
    })
}}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Grouping buttons

Placing buttons directly one after the other in your template will display them side by side. This lets you show a positive primary action next to a negative secondary action, for example, “Continue” and “Cancel”.

<button type="button" class="ons-btn">
  <span class="ons-btn__inner">Continue</span>
</button>
<button type="button" class="ons-btn ons-btn--secondary">
  <span class="ons-btn__inner">Cancel</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
    {{
        onsButton({
            "type": 'button',
            "text": 'Continue'
        })
    }}

    {{
        onsButton({
            "type": 'button',
            "text": 'Cancel',
            "variants": 'secondary'
        })
    }}
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Custom icon buttons

You can add an icon to a button using the parameters iconType and iconPosition.

There is specific guidance on how to use the available set of icons.

<div class="ons-u-mb-m">
  <button type="button" class="ons-btn">
    <span class="ons-btn__inner">
      <svg class="ons-svg-icon ons-u-mr-xs" viewBox="0 0 13 10" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
        <path d="M14.35,3.9l-.71-.71a.5.5,0,0,0-.71,0h0L5.79,10.34,3.07,7.61a.51.51,0,0,0-.71,0l-.71.71a.51.51,0,0,0,0,.71l3.78,3.78a.5.5,0,0,0,.71,0h0L14.35,4.6A.5.5,0,0,0,14.35,3.9Z" transform="translate(-1.51 -3.04)" />
      </svg>
      Done</span>
  </button>
</div>
<div>
  <button type="button" class="ons-btn ons-btn--secondary ons-btn--small">
    <span class="ons-btn__inner">
      <svg class="ons-svg-icon ons-u-mr-xs" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor">
        <path d="M11.86 10.23 8.62 6.99a4.63 4.63 0 1 0-6.34 1.64 4.55 4.55 0 0 0 2.36.64 4.65 4.65 0 0 0 2.33-.65l3.24 3.23a.46.46 0 0 0 .65 0l1-1a.48.48 0 0 0 0-.62Zm-5-3.32a3.28 3.28 0 0 1-2.31.93 3.22 3.22 0 1 1 2.35-.93Z" />
      </svg>
      Search</span>
  </button>
</div>
{% from "components/button/_macro.njk" import onsButton %}

<div class="ons-u-mb-m">
    {{
        onsButton({
            "type": 'button',
            "text": 'Done',
            "iconType": 'check'
        })
    }}
</div>
<div>
    {{
        onsButton({
            "type": 'button',
            "text": 'Search',
            "iconType": 'search',
            "variants": ['secondary', 'small']
        })
    }}
</div>
Name Type Required Description
text string true If html is set, this is not required. Text for the button. If html is provided, the text argument will be ignored.
html string true If text is set, this is not required. HTML for the button. If html is provided, the text argument will be ignored.
type string true Type of input or buttonbutton, submit or reset. Defaults to submit.
name string true Name for the button, if the button is a link the id attribute will be set instead
value string true Value for the button
url string false If provided will create a link and adds the relevant classes
variants array or string false An array of values or single value (string) to adjust the ‘button’ using available variants - small, secondary, ghost and disabled
id string false ID for the button
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
attributes object false HTML attributes (for example, data attributes) to add to the button component
listeners object false Creates a script element that adds an event listener to the element by id. Takes key { event } and value { function }
submitType string false If set to timer the button will only be disabled for a short time to stop double clicks from double submitting. If set to loader will create a loader button that includes the loading animation
iconType object false Object that contains the settings for adding icons to buttons.
noIcon boolean false Removes a button’s icon when set to true
newWindow boolean false Opens the next page in a new tab. Used for links to external pages
buttonStyle string false Can be set to print, exit or mobile. This will style the button with the relevant classes and icons
buttonContext string false Can be used to add context to a button’s text label for screen readers. For example, the “Hide this” button in the collapsible component requires context to help let a screen reader user know what the button hides.
dsExample boolean false Defaulted to true if set in Design System examples, will render a <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples

Icon

Name Type Required Description
iconType string true Name of the icon to be used
iconPosition string true Position of the icon in relation to the button text. Either set to before or after
{% from "components/icons/_macro.njk" import onsIcon %}

{% macro onsButton(params) %}

    {# Customisable button icon #}
    {% if params.iconType is defined and params.iconType %}
        {% set iconType = params.iconType %}
        {% if params.iconPosition is defined and params.iconPosition %}
            {% set iconPosition = params.iconPosition %}
        {% else %}
            {# Default icon position before label #}
            {% set iconPosition = "before" %}
        {% endif %}
    {% elif params.iconType is not defined and params.noIcon is not defined %}
        {# Opens in new tab #}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {# Download #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {# Print #}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {# Loader #}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {# CTA or mobile menu toggle #}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

    {% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}

    <{{ tag }}
        {% if params.url is defined and params.url %}
            href="{{ params.url }}"
            role="button"
        {% else %}
            type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
        {% endif %}
        class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "iconType": iconType,
                            "classes": 'ons-u-mr-xs'
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;

.ons-btn {
  background: transparent;
  border: 0;
  border-radius: 0;
  cursor: pointer;
  display: inline-block;
  font-family: inherit;
  font-size: 1rem;
  font-weight: $font-weight-bold;
  line-height: 1.35;
  margin: 0;
  padding: 0;
  position: relative;
  text-align: center;
  text-decoration: none;
  text-rendering: optimizeLegibility;
  vertical-align: top;
  white-space: nowrap;

  // Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
  &::after {
    border: ems($button-shadow-size) solid transparent;
    bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
    content: '';
    left: 0;
    position: absolute;
    right: 0;
    top: 0;
  }

  .ons-svg-icon {
    height: 18px;
    margin-top: -$button-shadow-size;
    vertical-align: middle;
    width: 18px;
  }

  &--search {
    .ons-svg-icon {
      @include mq(s, m) {
        margin-right: 0.5rem;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-radius: $input-radius;
    box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
    color: $color-text-inverse;
    display: inherit;
    padding: 0.7em 1em 0.8em;
    // Required for Google Tag Manager
    pointer-events: none;
    position: relative;
  }

  // When preceded by another button (for example, in a group)
  & + & {
    margin-left: 0.5rem;
  }

  // When focussed
  &:focus & {
    outline: 3px solid transparent;
  }

  &:focus &__inner {
    background: $color-focus;
    box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
    color: $color-text-link-focus;
  }

  &:focus:hover:not(:active) &__inner {
    background: darken($color-focus, 5%);
  }

  // When down
  &:active &,
  &:active:focus & {
    &__inner {
      background: $color-button;
      box-shadow: none;
      color: $color-text-inverse;
    }
  }

  &:active {
    top: ems($button-shadow-size);
  }

  &:focus,
  &:focus:hover {
    outline: none;
  }

  // Small buttons
  &--small,
  &--mobile {
    font-size: 0.9rem;
  }

  &--small & {
    &__inner {
      padding: 0.5em 0.7em;
      .ons-svg-icon {
        height: 16px;
        width: 16px;
      }
    }
  }

  &--small.ons-btn--ghost &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  // Secondary button style
  &--secondary & {
    &__inner {
      box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
    }
  }

  &--secondary &,
  &--secondary:active &,
  &--secondary:active:focus & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;

      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  // When hovered
  &:hover & {
    &__inner {
      background: darken($color-button, 5%);
    }
  }

  &--secondary:hover & {
    &__inner {
      background: darken($color-button-secondary, 5%);
    }
  }

  // Link button when hovered
  &--link:hover {
    text-decoration: none;
  }

  &--link:not(&--secondary) &,
  &--link:active:not(&--secondary) &,
  &--link:hover:not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--link:focus:not(:active):not(&--secondary) &,
  &--link:focus:hover:not(:active):not(&--secondary) & {
    &__inner {
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--loader &__inner {
    position: relative;
    transition: color 0.3s ease-in-out;
    .ons-svg-icon {
      height: 27px;
      left: 50%;
      margin: 0;
      opacity: 0;
      position: absolute;
      top: 50%;
      transform: translate(-50%, -50%);
      transition: opacity 0.3s ease-in-out;
      width: 27px;
    }
  }

  &--loader.ons-btn--small {
    .ons-svg-icon {
      height: 24px;
      width: 24px;
    }
  }

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      fill: $color-white;
      margin-left: 0 !important;
      opacity: 1;
    }
  }

  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      box-shadow: none;
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost-dark & {
    @extend .ons-btn--secondary;
    &__inner {
      background: transparent;
      border: 2px solid rgba(0, 0, 0, 0.6);
      color: $color-text;
    }
  }

  &--ghost,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

  &--ghost:active:focus {
    box-shadow: none;
    outline: 3px solid transparent;
  }

  &--ghost:focus:hover,
  &--mobile:focus:hover {
    outline: none;
  }

  &--ghost:hover &,
  &--mobile:hover & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
      border-color: $color-white;
    }
  }

  &--ghost:active &,
  &--mobile:active &,
  &--ghost:active:focus &,
  &--mobile:active:focus &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.2);
      border-color: rgba(255, 255, 255, 0.6);
      color: $color-text-inverse;
      .ons-svg-icon {
        fill: $color-text-inverse;
      }
    }
  }

  &--ghost.active:focus &,
  &--mobile.active:focus & {
    &__inner {
      background: $color-focus;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--ghost:focus &,
  &--mobile:focus & {
    &__inner {
      box-shadow: none;
      .ons-svg-icon {
        fill: $color-black;
      }
    }
  }

  &--mobile[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

  &--mobile {
    .ons-svg-icon {
      transform: rotate(90deg);
    }

    @include mq(m) {
      display: none;
    }
  }

  // Disabled buttons
  &--disabled {
    &:hover {
      cursor: not-allowed;
    }
    .ons-btn__inner {
      opacity: 0.4;
    }
  }
}

Help improve this component

Let us know how we could improve this component or share your user research findings. Discuss the ‘Button’ component on GitHub