Skip to main content

Button

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

When to use this component

Buttons are used to direct the user to perform a specific interaction. The copy used on the button should be clear, concise and direct.

How it works

Write button text in sentence case, describing the action it performs. For example ‘Save and continue’ or ‘Start now’.

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

There are 2 ways to use the button component. You can use HTML or, if you are using Nunjucks, you can use the Nunjucks macro.

Variants

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 complete.

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Secondary

Secondary buttons should be used for supplementary actions which users can take. Secondary buttons cannot exist without a primary button in the same context.

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Secondary (small)

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

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Call to action

The call to action button should be used when a link is the primary call to action on a page. Links styled as buttons are not accessible without certain attributes. We add role=button to the html which allows users that use voice commands to select the button.

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Call to action opening in a new window

If a call to action button needs to open in a new window, for example, for a web chat service, the newWindow parameter should be set to true. This will then provide a description to screen reader users to inform them the button will open a new window before they click it, as it would disable the back button in the browser.

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Ghost

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

Setting the buttonStyle param to exit adds the appropriate icon for a ‘sign out’ or ‘exit’ button.

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Disabled

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

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Loader

The loader button is used to help prevent user’s from clicking buttons multiple times when they are unsure if the action they have carried out has worked. This can lead to them submitting the form on the page twice. Setting SubmitType to loader will disable the button when clicked and will add a loading animation. This can be used when the button executes a process that can take some time to complete.

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Timer

The timer button is aimed at stopping forms being submitted twice when users double click the submit button. Setting SubmitType to timer will disable the button for one second on click.

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Print

The buttonStyle parameter can be set to print to render a print button. This will take care of adding iconography and classes for the print-button.js file to pick up. The button will not render until print-button.js has run, and will not be visible on printed pages.

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

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Download

The buttonStyle parameter can be set to download to render a download button. This will take care of adding iconography and the download attribute which will force the browser to save the file at the specified url.

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Grouping buttons

Placing buttons directly next to each other in your template will display them horizontally side by side. This will allow for a page to have two actions available to the user such as Continue and Cancel.

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

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

Icon

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

{% macro onsButton(params) %}

    {% if params.icon is defined and params.icon and params.icon != false %}
        {% set iconType = params.icon.iconType %}
        {% set iconPosition = params.icon.iconPosition %}
    {% elif params.icon is not defined %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            {% set iconType = "external-link" %}
            {% set iconPosition = "after" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
            {% set iconType = "download" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
            {% set iconType = "print" %}
            {% set iconPosition = "before" %}
        {% elif params.buttonStyle is defined and params.buttonStyle == "exit" %}
            {% set iconType = "exit" %}
            {% set iconPosition = "after" %}
        {% elif params.submitType is defined and params.submitType == "loader" %}
            {% set iconType = "loader" %}
            {% set iconPosition = "after" %}
        {% elif params.url is defined and params.url or params.buttonStyle is defined and params.buttonStyle == "mobile" %}
            {% set iconType = "chevron" %}
            {% set iconPosition = "after" %}
        {% endif %}
    {% endif %}

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

    <{{ tag }}
        {% if params.url is defined and params.url or params.buttonStyle == "exit" %}
            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 | isArray %}{% 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.disabled is defined and params.disabled %} ons-btn--disabled{% 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.buttonStyle == "exit" %} ons-btn--exit{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
        {% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
        {% if params.value is defined and params.value %}value="{{ params.value }}"{% endif %}
        {% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% elif params.name is defined and params.name and tag == "a" %}id="{{ params.name }}"{% endif %}
        {% if params.disabled is defined and params.disabled %} disabled{% endif %}
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
        {% if params.buttonStyle == "download" %} download{% endif %}
        {% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}
        >
        <span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
            {%- if iconPosition == "before" or iconPosition == "after" %}
                {%- if iconPosition == "before" %}
                    {{
                        onsIcon({
                            "icon": iconType
                        })
                    }}
                {% endif -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
                {%- if iconPosition == "after" %}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                {% endif -%}
            {% elif iconPosition == "only" -%}
                {{
                    onsIcon({
                        "icon": iconType
                    })
                }}
                <span class="ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
            {% else -%}
                {{- params.html | safe if params.html is defined and params.html else params.text -}}
            {% endif -%}
        </span>
        {% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
            <span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
        {% endif %}
        {% if params.buttonContext is defined and params.buttonContext %}
            <span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
        {% endif %}
        {% if params.listeners %}
            <script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
                {% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
                    document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
                {% endfor %}
            </script>
        {% endif %}
    </{{ tag }}>
{% endmacro %}
$button-border-height: 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;

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

  .ons-svg-icon {
    fill: $color-text-inverse;
    height: 0.8rem;
    margin: 0 0 0.1rem 0.5rem;
    vertical-align: middle;
    width: 0.8rem;
  }

  &--search {
    .svg-icon {
      height: 21px;
      margin: 0;
      vertical-align: top;
      width: 21px;

      @include mq(s, m) {
        margin-left: -2px;
      }
    }
  }

  &__inner {
    background: $color-button;
    border-bottom: ems($button-border-height) solid rgba(0, 0, 0, 0.6);
    border-radius: $input-radius;
    color: $color-text-inverse;
    display: inherit;
    padding: 0.75em 1em;
    // Required for Google Tag Manager
    pointer-events: none;
  }

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

  // When focussed
  &:focus:not(:active):not(:hover) {
    outline: 3px solid transparent;
  }

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

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

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

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus,
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):focus:hover {
    outline: none;
  }

  // When clicked
  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active {
    padding-top: ems(3px);
  }

  &:not([class*='ons-btn--ghost']):not([class*='ons-btn--mobile']):active &__inner {
    border-bottom: 0;
  }

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

  &--small &,
  &--mobile & {
    &__inner {
      padding: 0.5em 0.7em;
    }
  }

  &--inline & {
    &__inner {
      padding: 0.5rem 1rem;
    }
  }

  &--secondary &,
  &--print &,
  &--download & {
    &__inner {
      background: $color-button-secondary;
      color: $color-text;
      font-weight: normal;
      .ons-svg-icon {
        fill: $color-text;
      }
    }
  }

  &--print &,
  &--download & {
    &__inner {
      .ons-svg-icon {
        height: 1rem;
        margin: 0 0.5rem 0.1rem 0;
        width: 1rem;
      }
    }
  }

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

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

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

  // Link button when focussed
  &--link:focus:not(:active):not(:hover) &__inner {
    background: $color-focus;
    color: $color-text-link-focus;
  }

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

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

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

  &--loader.ons-is-loading &__inner {
    color: transparent;
    .ons-svg-icon {
      opacity: 1;
    }
  }

  // Spooky Buttons
  &--ghost &,
  &--mobile & {
    &__inner {
      background: transparent;
      border: 2px solid rgba(255, 255, 255, 0.6);
      color: $color-white;
      .ons-svg-icon {
        fill: $color-white;
      }
    }
  }

  &--ghost:active &,
  &--mobile:active & {
    &__inner {
      border-color: $color-white;
    }
  }

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

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

  &--ghost:hover &,
  &--mobile:hover &,
  &--ghost.active &,
  &--mobile.active & {
    &__inner {
      background: rgba(0, 0, 0, 0.1);
    }
  }

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

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

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

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

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

Help improve this component

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