Skip to main content

User testing

Help us improve this service. Take part in a short online exercise

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"><span class="ons-btn__text">Save and continue</span>
  </span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "text": "Save and continue"
    })
}}
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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"><span class="ons-btn__text">Save and continue</span>
  </span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "text": "Save and continue"
    })
}}
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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"><span class="ons-btn__text">Add</span>
  </span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "type": 'button',
        "text": 'Add',
        "variants": 'small'
    })
}}
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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"><span class="ons-btn__text">Add a person</span>
  </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 (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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"><span class="ons-btn__text">Add</span>
  </span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "type": 'button',
        "text": 'Add',
        "variants": ['secondary', 'small']
    })
}}
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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"><span class="ons-btn__text">Get started</span>
    <svg class="ons-svg-icon ons-u-ml-xs" viewBox="0 0 17 13" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
      <path d="m10 .2-.9.9c-.1.1-.1.4 0 .5l4 4H.6c-.2 0-.4.2-.4.4v1.2c0 .2.2.4.4.4h12.5l-3.9 3.7c-.2.2-.2.4 0 .6l.8.9c.2.2.4.2.6 0L16.8 7c.2-.2.2-.4 0-.6L10.7.3c-.3-.2-.5-.2-.7-.1z" />
    </svg>
  </span>
</a>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "text": 'Get started',
        "url": '#0'
    })
}}
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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"><span class="ons-btn__text">Web chat</span>
    <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({
        "text": 'Web chat',
        "url": '#0',
        "newWindow": true
    })
}}
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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"><span class="ons-btn__text">Save and sign out</span>
      <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({
            "text": 'Save and sign out',
            "url": '#0',
            "variants": 'ghost',
            "iconType": "exit",
            "iconPosition": "after"
        })
    }}
</div>
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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="submit" class="ons-btn ons-btn--disabled" disabled="true">
  <span class="ons-btn__inner"><span class="ons-btn__text">Submit</span>
  </span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
    onsButton({
        "text": 'Submit',
        "variants": 'disabled',
        "attributes": {
            "disabled": "true"
        }
    })
}}
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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"><span class="ons-btn__text">Submit</span>
      <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 (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

Timer

The timer button can be used to prevent forms being submitted twice when users double-click the submit button. Setting "submitType": 'timer' 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"><span class="ons-btn__text">Submit</span>
    </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 (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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>
    <span class="ons-btn__text">Print this page</span></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 (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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>
    <span class="ons-btn__text">Save answers as PDF</span></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 (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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="submit" class="ons-btn">
  <span class="ons-btn__inner"><span class="ons-btn__text">Continue</span>
  </span>
</button>
<button type="button" class="ons-btn ons-btn--secondary">
  <span class="ons-btn__inner"><span class="ons-btn__text">Cancel</span>
  </span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
    {{
        onsButton({
            "text": 'Continue'
        })
    }}

    {{
        onsButton({
            "type": 'button',
            "text": 'Cancel',
            "variants": 'secondary'
        })
    }}
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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>
      <span class="ons-btn__text">Done</span></span>
  </button>
</div>
<div>
  <button type="submit" 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>
      <span class="ons-btn__text">Search</span></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({
            "text": 'Search',
            "iconType": 'search',
            "variants": ['secondary', 'small']
        })
    }}
</div>
Name Type Required Description
text string true (unless html is set) Text label for the button
html string true (unless text is set) HTML for the button label
type string false Sets the HTML type attribute for the <button>. Can be set to either: “submit” or “reset”. Defaults to “button”.
id string false Sets the HTML id of the button
name string false Sets the HTML name attribute for the <button>. Not valid if url is set.
value string false Sets the HTML value attribute for the <button>. Not valid if url is set.
classes string false Classes to add to the button component
innerClasses string false Classes to add to the inner button element
variants array or string false An array of values or single value (string) to adjust the component using available variants: “small”, “secondary”, “ghost” and “disabled”
buttonStyle string false Set to “print”, “exit” or “mobile” to style the button with the relevant classes and icons
submitType string false Set to “loader” to disable the button when selected and show an animated loading icon. Set to “timer” only to disable for a short time to prevent forms being submitted twice when users double-click the button.
url string false Creates an HTML hyperlink <a> element in place of the <button> element, with the required classes and attributes. Set the URL for the href attribute.
newWindow boolean false Set to “true” to make the button open the page set by url in a new tab. Used for links to external pages
newWindowDescription string false Use to set context after the newWindow button’s text label for screen readers. Defaults to “opens in a new window”
iconType string false Adds an icon to the button, before the label, by setting the icon type
iconPosition string false Sets the icon position of the button.
noIcon boolean false Set to “true” to remove the button’s default icon
buttonContext string false Use to add context after 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.
attributes object false HTML attributes (for example, data attributes) to add to the button component
removeDownloadAttribute boolean false Removes the download attribute on the download variant when set to “true”. Use when the download button needs to be redirected, for example when a session has expired. You must also set the Content-Disposition header to make sure the file is downloaded
listeners object false Creates a <script> element that adds an event listener to the element by id. Takes key { event } and value { function }
dsExample boolean false Defaults to true if set in Design System examples, will render an <a> tag instead of <button> to stop default submit behaviour of buttons in forms - only for use in DS examples
{% 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.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url %}
            {% set iconType = "arrow-next" %}
            {% 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 and tag != "a" %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ 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" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} 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 -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "iconType": iconType,
                        "classes": 'ons-u-ml-xs'
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "iconType": iconType
                    })
                }}
                <span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                <span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% 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 focused
  &: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;
    }
  }

  &--text-link {
    vertical-align: baseline;
  }

  &--text-link & {
    &__inner {
      background: transparent;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      font-weight: normal;
      padding: 0;
      .ons-svg-icon {
        fill: $color-text-link;
      }
    }
  }

  &--text-link-inverse & {
    &__inner {
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--text-link:hover &,
  &--text-link:active &,
  &--text-link.active & {
    &__inner {
      background: none;
      color: $color-text-link-hover;
      .ons-svg-icon {
        fill: $color-text-link-hover;
      }
    }
  }

  &--text-link-inverse:hover &,
  &--text-link-inverse:active &,
  &--text-link-inverse.active & {
    &__inner {
      color: $color-branded-tint;
      .ons-svg-icon {
        fill: $color-branded-tint;
      }
    }
  }

  &--text-link:focus:hover & {
    &__inner {
      color: $color-black;
    }
  }

  &--text-link:focus &,
  &--text-link.active:focus &,
  &--text-link:active:focus & {
    &__inner {
      background-color: $color-focus;
      box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
      color: $color-text-link-focus;
      .ons-svg-icon {
        fill: $color-text-link-focus;
      }
    }
  }

  &--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,
  &--text-link,
  &--mobile {
    &:active,
    .active {
      top: 0;
    }
  }

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

  &--ghost:focus:hover,
  &--text-link: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'],
  &--text-link[aria-expanded='true'] {
    .ons-svg-icon {
      transform: rotate(270deg);
    }
  }

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

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

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

  &--dropdown {
    @extend .ons-btn--ghost;
    @extend .ons-btn--mobile;

    width: 100%;

    .ons-btn__inner {
      background: $color-branded-tint;
      border: none;
      border-radius: 0;
      box-shadow: none;
      color: $color-text-link;
      display: block;
      font-size: 1rem;
      font-weight: normal;
      padding: 0.6rem 1rem;
      text-align: left;

      .ons-svg-icon {
        fill: $color-text-link;
        float: right;
        margin-top: 3px;
      }
    }

    &:active,
    &:active:focus {
      .ons-btn__inner {
        background: $color-branded-secondary;
        color: $color-white;
        .ons-svg-icon {
          fill: $color-white;
        }
      }
    }
  }
}

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