Button
Buttons help users carry out important actions on a page like starting a survey or saving their answers.
<button type="submit" class="ons-btn">
<span class="ons-btn__inner"><span class="ons-btn__text">Save and continue</span>
</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"text": "Save and continue"
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
When to use this component
Use a button to help direct users to perform a specific action. They should be used to start a process, save users information, and progress through a service.
How to use this component
Write button text in sentence case, describing the action it performs. The button label should be short, clear and direct. For example ‘Save and continue’ or ‘Sign in’.
Align the primary action button to the left edge of a form.
Primary (default)
Use a primary button for the main call to action on a page.
Avoid using multiple primary buttons on the same page because it will reduce the impact and make it hard for users to know what to do next.
<button type="submit" class="ons-btn">
<span class="ons-btn__inner"><span class="ons-btn__text">Save and continue</span>
</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"text": "Save and continue"
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Variants
To use an alternative type of button, set the variants
parameter to either a single value or an array of multiple values. For example, "variants": 'small'
or "variants": ['small', 'secondary']
.
Small
In certain circumstances there may be the need for multiple primary actions to exist on a page. The small primary button should be used in this scenario only when each action has the same context, for example, a list containing business surveys that a user needs to start.
<button type="button" class="ons-btn ons-btn--small">
<span class="ons-btn__inner"><span class="ons-btn__text">Add</span>
</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"type": 'button',
"text": 'Add',
"variants": 'small'
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Secondary
Use secondary buttons in combination with a primary button for secondary actions on the page. Avoid using too many secondary buttons on the same page as it can make hard for users to know what to do next.
<button type="button" class="ons-btn ons-btn--secondary">
<span class="ons-btn__inner"><span class="ons-btn__text">Add a person</span>
</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"type": 'button',
"text": 'Add a person',
"variants": 'secondary'
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Secondary (small)
A small secondary button should be used within the same context of a primary small button when there is an additional action available along with the primary action.
<button type="button" class="ons-btn ons-btn--secondary ons-btn--small">
<span class="ons-btn__inner"><span class="ons-btn__text">Add</span>
</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"type": 'button',
"text": 'Add',
"variants": ['secondary', 'small']
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Call to action
The call to action button should be used when a link to a new page is the primary call to action on a page. For example, a “Start survey” button.
Links simply styled as buttons are not accessible to users who navigate a web page with voice commands. Setting the url
parameter will create a link with role=button
which will let these users select the button.
<a href="#0" role="button" class="ons-btn ons-btn--link ons-js-submit-btn">
<span class="ons-btn__inner"><span class="ons-btn__text">Get started</span>
<svg class="ons-svg-icon ons-u-ml-xs" viewBox="0 0 17 13" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
<path d="m10 .2-.9.9c-.1.1-.1.4 0 .5l4 4H.6c-.2 0-.4.2-.4.4v1.2c0 .2.2.4.4.4h12.5l-3.9 3.7c-.2.2-.2.4 0 .6l.8.9c.2.2.4.2.6 0L16.8 7c.2-.2.2-.4 0-.6L10.7.3c-.3-.2-.5-.2-.7-.1z" />
</svg>
</span>
</a>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"text": 'Get started',
"url": '#0'
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Call to action opening in a new window
Use this button when a page needs to open in a new window, for example, for a web chat service.
Set the newWindow
parameter to true
. This adds a warning for screen reader users so they know a new window will open when they select the button. This helps them understand why the back button in the browser is disabled on the new page.
<a href="#0" role="button" class="ons-btn ons-btn--link ons-js-submit-btn" target="_blank" rel="noopener">
<span class="ons-btn__inner"><span class="ons-btn__text">Web chat</span>
<svg class="ons-svg-icon ons-u-ml-xs" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
<path d="M13.5,9H13a.5.5,0,0,0-.5.5v3h-9v-9h3A.5.5,0,0,0,7,3V2.5A.5.5,0,0,0,6.5,2h-4a.5.5,0,0,0-.5.5v11a.5.5,0,0,0,.5.5h11a.5.5,0,0,0,.5-.5v-4A.5.5,0,0,0,13.5,9Z" transform="translate(-2 -1.99)" />
<path d="M8.83,7.88a.51.51,0,0,0,.71,0l2.31-2.32,1.28,1.28A.51.51,0,0,0,14,6.49v-4a.52.52,0,0,0-.5-.5h-4A.51.51,0,0,0,9,2.52a.58.58,0,0,0,.14.33l1.28,1.28L8.12,6.46a.51.51,0,0,0,0,.71Z" transform="translate(-2 -1.99)" />
</svg>
</span>
<span class="ons-btn__new-window-description ons-u-vh">opens in a new window</span>
</a>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"text": 'Web chat',
"url": '#0',
"newWindow": true
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Ghost
The ghosted button style is for use in the header or footer. This can be used to allow a user to exit or save and sign out of a service.
Setting the iconType
parameter to exit
adds an appropriate icon for a ‘sign out’ or ‘exit’ button.
<div style="padding: 1.5rem; background: #206095">
<a href="#0" role="button" class="ons-btn ons-btn--ghost ons-btn--link ons-js-submit-btn">
<span class="ons-btn__inner"><span class="ons-btn__text">Save and sign out</span>
<svg class="ons-svg-icon ons-u-ml-xs" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
<path d="M13.85,7.65l-2.5-2.5a.5.5,0,0,0-.71,0,.48.48,0,0,0-.15.36V7h-3a.5.5,0,0,0-.5.5v1a.5.5,0,0,0,.5.5h3v1.5A.49.49,0,0,0,11,11a.48.48,0,0,0,.34-.14l2.51-2.5a.49.49,0,0,0,0-.68Z" transform="translate(-2 -2)" />
<path d="M8.5,14h-6a.5.5,0,0,1-.5-.5V2.5A.5.5,0,0,1,2.5,2h6a.5.5,0,0,1,.5.5V3a.5.5,0,0,1-.5.5h-5v9h5A.5.5,0,0,1,9,13v.5A.5.5,0,0,1,8.5,14Z" transform="translate(-2 -2)" />
</svg>
</span>
</a>
</div>
{% from "components/button/_macro.njk" import onsButton %}
<div style="padding: 1.5rem; background: #206095">
{{
onsButton({
"text": 'Save and sign out',
"url": '#0',
"variants": 'ghost',
"iconType": "exit",
"iconPosition": "after"
})
}}
</div>
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Disabled
Disabled buttons have poor contrast and can confuse some users. Only use disabled buttons if research shows it makes the page easier to understand. For example, the “Send message” button on the Send and reply to messages pattern is disabled until a message is entered into the field.
Use "variant": 'disabled'
with the disabled=true
attribute parameter for buttons that have no event/action but need to be displayed.
<button type="submit" class="ons-btn ons-btn--disabled" disabled="true">
<span class="ons-btn__inner"><span class="ons-btn__text">Submit</span>
</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"text": 'Submit',
"variants": 'disabled',
"attributes": {
"disabled": "true"
}
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Loader
The loader button should be used when the button starts a process that can take longer than expected to complete.
Using it will prevent a form being submitted more than once if a user tries to select the button multiple times.
Setting "submitType": 'loader'
will disable the button when selected and show an animated loading icon.
<form onsubmit="return false;">
<button type="submit" class="ons-btn ons-btn--loader ons-js-loader ons-js-submit-btn">
<span class="ons-btn__inner"><span class="ons-btn__text">Submit</span>
<svg class="ons-svg-icon ons-u-ml-xs" xmlns="http://www.w3.org/2000/svg" focusable="false" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" fill="currentcolor">
<rect x="0" y="0" width="100" height="100" fill="none"></rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(0 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(30 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.08333333333333333s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(60 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.16666666666666666s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(90 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.25s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(120 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.3333333333333333s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(150 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.4166666666666667s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(180 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.5s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(210 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.5833333333333334s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(240 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.6666666666666666s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(270 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.75s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(300 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.8333333333333334s' repeatCount='indefinite' />
</rect>
<rect x='46.5' y='40' width='7' height='20' rx='5' ry='5' transform='rotate(330 50 50) translate(0 -30)'>
<animate attributeName='opacity' from='1' to='0' dur='1s' begin='0.9166666666666666s' repeatCount='indefinite' />
</rect>
</svg>
</span>
</button>
</form>
{% from "components/button/_macro.njk" import onsButton %}
<form onsubmit="return false;">
{{
onsButton({
"text": 'Submit',
"submitType": "loader"
})
}}
</form>
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Timer
The timer button can be used to prevent forms being submitted twice when users double-click the submit button. Setting "submitType": 'timer'
will disable the button for one second after it’s selected.
<form onsubmit="return false;">
<button type="submit" class="ons-btn ons-js-timer ons-js-submit-btn">
<span class="ons-btn__inner"><span class="ons-btn__text">Submit</span>
</span>
</button>
</form>
{% from "components/button/_macro.njk" import onsButton %}
<form onsubmit="return false;">
{{
onsButton({
"text": 'Submit',
"submitType": "timer"
})
}}
</form>
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Setting "buttonStyle": 'print'
will show a button with a print icon and add classes used in the print-button.js
file.
The button will not show until the JavaScript has run, and will not be shown on a printed page.
<button type="button" class="ons-btn ons-btn--small ons-btn--secondary ons-btn--print ons-u-d-no ons-js-print-btn">
<span class="ons-btn__inner">
<svg class="ons-svg-icon ons-u-mr-xs" viewBox="0 0 20 16" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
<path d="M17 4H3C1.3 4 0 5.2 0 6.8v5.5h4V16h12v-3.7h4V6.8C20 5.2 18.7 4 17 4zm-3 10H6V9h8v5zm3-6a1 1 0 1 1 0-2 1 1 0 0 1 0 2zm-1-8H4v3h12V0z" />
</svg>
<span class="ons-btn__text">Print this page</span></span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"type": 'button',
"text": 'Print this page',
"buttonStyle": 'print',
"variants": ['small', 'secondary']
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Download
Setting "buttonStyle": 'download'
will show a button with a download icon and add the download
attribute to make the browser save the file at the specified url
.
<a href="#0" role="button" class="ons-btn ons-btn--small ons-btn--secondary ons-btn--link ons-js-submit-btn ons-btn--download" download>
<span class="ons-btn__inner">
<svg class="ons-svg-icon ons-u-mr-xs" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
<path d="M5.6 9a.48.48 0 0 0 .7 0l3-3.2a.48.48 0 0 0 0-.7C9.3 5 9.2 5 9 5H7.5V.5A.47.47 0 0 0 7 0H5a.47.47 0 0 0-.5.5V5H3a.47.47 0 0 0-.5.5.37.37 0 0 0 .1.3Z" />
<path d="M11.5 9H11a.47.47 0 0 0-.5.5v1h-9v-1A.47.47 0 0 0 1 9H.5a.47.47 0 0 0-.5.5v2a.47.47 0 0 0 .5.5h11a.47.47 0 0 0 .5-.5v-2a.47.47 0 0 0-.5-.5Z" />
</svg>
<span class="ons-btn__text">Save answers as PDF</span></span>
</a>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"buttonStyle": 'download',
"text": 'Save answers as PDF',
"url": '#0',
"variants": ['small', 'secondary']
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Grouping buttons
Placing buttons directly one after the other in your template will display them side by side. This lets you show a positive primary action next to a negative secondary action, for example, “Continue” and “Cancel”.
<button type="submit" class="ons-btn">
<span class="ons-btn__inner"><span class="ons-btn__text">Continue</span>
</span>
</button>
<button type="button" class="ons-btn ons-btn--secondary">
<span class="ons-btn__inner"><span class="ons-btn__text">Cancel</span>
</span>
</button>
{% from "components/button/_macro.njk" import onsButton %}
{{
onsButton({
"text": 'Continue'
})
}}
{{
onsButton({
"type": 'button',
"text": 'Cancel',
"variants": 'secondary'
})
}}
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Custom icon buttons
You can add an icon to a button using the parameters iconType
and iconPosition
.
There is specific guidance on how to use the available set of icons.
<div class="ons-u-mb-m">
<button type="button" class="ons-btn">
<span class="ons-btn__inner">
<svg class="ons-svg-icon ons-u-mr-xs" viewBox="0 0 13 10" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
<path d="M14.35,3.9l-.71-.71a.5.5,0,0,0-.71,0h0L5.79,10.34,3.07,7.61a.51.51,0,0,0-.71,0l-.71.71a.51.51,0,0,0,0,.71l3.78,3.78a.5.5,0,0,0,.71,0h0L14.35,4.6A.5.5,0,0,0,14.35,3.9Z" transform="translate(-1.51 -3.04)" />
</svg>
<span class="ons-btn__text">Done</span></span>
</button>
</div>
<div>
<button type="submit" class="ons-btn ons-btn--secondary ons-btn--small">
<span class="ons-btn__inner">
<svg class="ons-svg-icon ons-u-mr-xs" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor">
<path d="M11.86 10.23 8.62 6.99a4.63 4.63 0 1 0-6.34 1.64 4.55 4.55 0 0 0 2.36.64 4.65 4.65 0 0 0 2.33-.65l3.24 3.23a.46.46 0 0 0 .65 0l1-1a.48.48 0 0 0 0-.62Zm-5-3.32a3.28 3.28 0 0 1-2.31.93 3.22 3.22 0 1 1 2.35-.93Z" />
</svg>
<span class="ons-btn__text">Search</span></span>
</button>
</div>
{% from "components/button/_macro.njk" import onsButton %}
<div class="ons-u-mb-m">
{{
onsButton({
"type": 'button',
"text": 'Done',
"iconType": 'check'
})
}}
</div>
<div>
{{
onsButton({
"text": 'Search',
"iconType": 'search',
"variants": ['secondary', 'small']
})
}}
</div>
{% from "components/icons/_macro.njk" import onsIcon %}
{% macro onsButton(params) %}
{# Customisable button icon #}
{% if params.iconType is defined and params.iconType %}
{% set iconType = params.iconType %}
{% if params.iconPosition is defined and params.iconPosition %}
{% set iconPosition = params.iconPosition %}
{% else %}
{# Default icon position before label #}
{% set iconPosition = "before" %}
{% endif %}
{% elif params.iconType is not defined and params.noIcon is not defined %}
{# Opens in new tab #}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
{% set iconType = "external-link" %}
{% set iconPosition = "after" %}
{# Download #}
{% elif params.buttonStyle is defined and params.buttonStyle == "download" %}
{% set iconType = "download" %}
{% set iconPosition = "before" %}
{# Print #}
{% elif params.buttonStyle is defined and params.buttonStyle == "print" %}
{% set iconType = "print" %}
{% set iconPosition = "before" %}
{# Loader #}
{% elif params.submitType is defined and params.submitType == "loader" %}
{% set iconType = "loader" %}
{% set iconPosition = "after" %}
{# CTA or mobile menu toggle #}
{% elif params.buttonStyle is defined and params.buttonStyle == "mobile" %}
{% set iconType = "chevron" %}
{% set iconPosition = "after" %}
{% elif params.url is defined and params.url %}
{% set iconType = "arrow-next" %}
{% set iconPosition = "after" %}
{% endif %}
{% endif %}
{% set tag = "a" if params.url or params.dsExample is defined and params.dsExample else "button" %}
<{{ tag }}
{% if params.url is defined and params.url %}
href="{{ params.url }}"
role="button"
{% else %}
type="{{ params.type if params.type is defined and params.type else ('button' if params.buttonStyle == "print" else 'submit') }}"
{% endif %}
class="ons-btn{% if params.classes is defined and params.classes %} {{ params.classes }}{% endif %}{% if params.variants is defined and params.variants %}{% if params.variants is not string %}{% for variant in params.variants %} ons-btn--{{ variant }}{% endfor %}{% else %} ons-btn--{{ params.variants }}{% endif %}{% endif %}{% if params.url is defined and params.url %} ons-btn--link ons-js-submit-btn{% endif %}{% if params.buttonStyle == "download" %} ons-btn--download{% endif %}{% if params.buttonStyle == "print" %} ons-btn--print ons-u-d-no ons-js-print-btn{% endif %}{% if params.submitType == "loader" %} ons-btn--loader ons-js-loader ons-js-submit-btn{% endif %}{% if params.submitType == "timer" %} ons-js-timer ons-js-submit-btn{% endif %}"
{% if params.id is defined and params.id %}id="{{ params.id }}"{% endif %}
{% if params.value is defined and params.value and tag != "a" %}value="{{ params.value }}"{% endif %}
{% if params.name is defined and params.name and tag != "a" %}name="{{ params.name }}"{% endif %}
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}target="_blank" rel="noopener"{% endif %}
{% if params.buttonStyle == "download" and (params.removeDownloadAttribute is not defined or not params.removeDownloadAttribute or params.removeDownloadAttribute != true) %} download{% endif %}
{% if params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params.attributes is mapping and params.attributes.items else params.attributes) %} {{attribute}}="{{value}}"{% endfor %}{% endif %}
>
<span class="ons-btn__inner{% if params.innerClasses is defined and params.innerClasses %} {{ params.innerClasses }}{% endif %}">
{%- if iconPosition == "before" or iconPosition == "after" %}
{%- if iconPosition == "before" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-mr-xs'
})
}}
{% endif -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{%- if iconPosition == "after" %}
{{
onsIcon({
"iconType": iconType,
"classes": 'ons-u-ml-xs'
})
}}
{% endif -%}
{% elif iconPosition == "only" -%}
{{
onsIcon({
"iconType": iconType
})
}}
<span class="ons-btn__text ons-u-vh@xxs@s">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% else -%}
<span class="ons-btn__text">{{- params.html | safe if params.html is defined and params.html else params.text -}}</span>
{% endif -%}
</span>
{% if params.url is defined and params.url and params.newWindow is defined and params.newWindow %}
<span class="ons-btn__new-window-description ons-u-vh">{{ params.newWindowDescription | default("opens in a new window") }}</span>
{% endif %}
{% if params.buttonContext is defined and params.buttonContext %}
<span class="ons-btn__context ons-u-vh">{{ params.buttonContext }}</span>
{% endif %}
{% if params.listeners %}
<script{% if csp_nonce %} nonce="{{ csp_nonce() }}"{% endif %}>
{% for listener, value in (params.listeners.items() if params.listeners is mapping and params.listeners.items else params.listeners) %}
document.getElementById("{{ params.id }}").addEventListener('{{ listener }}', function(){ {{ value }} });
{% endfor %}
</script>
{% endif %}
</{{ tag }}>
{% endmacro %}
$button-shadow-size: 3px;
.ons-btn {
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: 1rem;
font-weight: $font-weight-bold;
line-height: 1.35;
margin: 0;
padding: 0;
position: relative;
text-align: center;
text-decoration: none;
text-rendering: optimizeLegibility;
vertical-align: top;
white-space: nowrap;
// Transparent border for IE11 High Contrast mode support due to 'border: 0' on buttons
&::after {
border: ems($button-shadow-size) solid transparent;
bottom: -(ems($button-shadow-size)); // makes sure button shadow is selectable
content: '';
left: 0;
position: absolute;
right: 0;
top: 0;
}
.ons-svg-icon {
height: 18px;
margin-top: -$button-shadow-size;
vertical-align: middle;
width: 18px;
}
&--search {
.ons-svg-icon {
@include mq(s, m) {
margin-right: 0.5rem;
}
}
}
&__inner {
background: $color-button;
border-radius: $input-radius;
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button, 15%);
color: $color-text-inverse;
display: inherit;
padding: 0.7em 1em 0.8em;
// Required for Google Tag Manager
pointer-events: none;
position: relative;
}
// When preceded by another button (for example, in a group)
& + & {
margin-left: 0.5rem;
}
// When focused
&:focus & {
outline: 3px solid transparent;
}
&:focus &__inner {
background: $color-focus;
box-shadow: 0 ems($button-shadow-size) 0 $color-text-link-focus;
color: $color-text-link-focus;
}
&:focus:hover:not(:active) &__inner {
background: darken($color-focus, 5%);
}
// When down
&:active &,
&:active:focus & {
&__inner {
background: $color-button;
box-shadow: none;
color: $color-text-inverse;
}
}
&:active {
top: ems($button-shadow-size);
}
&:focus,
&:focus:hover {
outline: none;
}
// Small buttons
&--small,
&--mobile {
font-size: 0.9rem;
}
&--small & {
&__inner {
padding: 0.5em 0.7em;
.ons-svg-icon {
height: 16px;
width: 16px;
}
}
}
&--small.ons-btn--ghost &,
&--mobile & {
&__inner {
padding: 0.5em 0.7em;
}
}
// Secondary button style
&--secondary & {
&__inner {
box-shadow: 0 ems($button-shadow-size) 0 darken($color-button-secondary, 50%);
}
}
&--secondary &,
&--secondary:active &,
&--secondary:active:focus & {
&__inner {
background: $color-button-secondary;
color: $color-text;
font-weight: normal;
.ons-svg-icon {
fill: $color-text;
}
}
}
// When hovered
&:hover & {
&__inner {
background: darken($color-button, 5%);
}
}
&--secondary:hover & {
&__inner {
background: darken($color-button-secondary, 5%);
}
}
// Link button when hovered
&--link:hover {
text-decoration: none;
}
&--link:not(&--secondary) &,
&--link:active:not(&--secondary) &,
&--link:hover:not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--link:focus:not(:active):not(&--secondary) &,
&--link:focus:hover:not(:active):not(&--secondary) & {
&__inner {
.ons-svg-icon {
fill: $color-text;
}
}
}
&--loader &__inner {
position: relative;
transition: color 0.3s ease-in-out;
.ons-svg-icon {
height: 27px;
left: 50%;
margin: 0;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.3s ease-in-out;
width: 27px;
}
}
&--loader.ons-btn--small {
.ons-svg-icon {
height: 24px;
width: 24px;
}
}
&--loader.ons-is-loading &__inner {
color: transparent;
.ons-svg-icon {
fill: $color-white;
margin-left: 0 !important;
opacity: 1;
}
}
&--text-link {
vertical-align: baseline;
}
&--text-link & {
&__inner {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
font-weight: normal;
padding: 0;
.ons-svg-icon {
fill: $color-text-link;
}
}
}
&--text-link-inverse & {
&__inner {
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
&--text-link:hover &,
&--text-link:active &,
&--text-link.active & {
&__inner {
background: none;
color: $color-text-link-hover;
.ons-svg-icon {
fill: $color-text-link-hover;
}
}
}
&--text-link-inverse:hover &,
&--text-link-inverse:active &,
&--text-link-inverse.active & {
&__inner {
color: $color-branded-tint;
.ons-svg-icon {
fill: $color-branded-tint;
}
}
}
&--text-link:focus:hover & {
&__inner {
color: $color-black;
}
}
&--text-link:focus &,
&--text-link.active:focus &,
&--text-link:active:focus & {
&__inner {
background-color: $color-focus;
box-shadow: 0 -2px $color-focus, 0 4px $color-text-link-focus !important;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost &,
&--mobile & {
&__inner {
background: transparent;
border: 2px solid rgba(255, 255, 255, 0.6);
box-shadow: none;
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost-dark & {
@extend .ons-btn--secondary;
&__inner {
background: transparent;
border: 2px solid rgba(0, 0, 0, 0.6);
color: $color-text;
}
}
&--ghost,
&--text-link,
&--mobile {
&:active,
.active {
top: 0;
}
}
&--ghost:active:focus {
box-shadow: none;
outline: 3px solid transparent;
}
&--ghost:focus:hover,
&--text-link:focus:hover,
&--mobile:focus:hover {
outline: none;
}
&--ghost:hover &,
&--mobile:hover & {
&__inner {
background: rgba(0, 0, 0, 0.1);
border-color: $color-white;
}
}
&--ghost:active &,
&--mobile:active &,
&--ghost:active:focus &,
&--mobile:active:focus &,
&--ghost.active &,
&--mobile.active & {
&__inner {
background: rgba(0, 0, 0, 0.2);
border-color: rgba(255, 255, 255, 0.6);
color: $color-text-inverse;
.ons-svg-icon {
fill: $color-text-inverse;
}
}
}
&--ghost.active:focus &,
&--mobile.active:focus & {
&__inner {
background: $color-focus;
color: $color-text-link-focus;
.ons-svg-icon {
fill: $color-text-link-focus;
}
}
}
&--ghost:focus &,
&--mobile:focus & {
&__inner {
box-shadow: none;
.ons-svg-icon {
fill: $color-black;
}
}
}
&--mobile[aria-expanded='true'],
&--text-link[aria-expanded='true'] {
.ons-svg-icon {
transform: rotate(270deg);
}
}
&--mobile,
&--text-link {
.ons-svg-icon {
transform: rotate(90deg);
}
@include mq(l) {
display: none;
}
}
// Disabled buttons
&--disabled {
&:hover {
cursor: not-allowed;
}
.ons-btn__inner {
opacity: 0.4;
}
}
&--dropdown {
@extend .ons-btn--ghost;
@extend .ons-btn--mobile;
width: 100%;
.ons-btn__inner {
background: $color-branded-tint;
border: none;
border-radius: 0;
box-shadow: none;
color: $color-text-link;
display: block;
font-size: 1rem;
font-weight: normal;
padding: 0.6rem 1rem;
text-align: left;
.ons-svg-icon {
fill: $color-text-link;
float: right;
margin-top: 3px;
}
}
&:active,
&:active:focus {
.ons-btn__inner {
background: $color-branded-secondary;
color: $color-white;
.ons-svg-icon {
fill: $color-white;
}
}
}
}
}
Help improve this component
Let us know how we could improve this component or share your user research findings. Discuss the ‘Button’ component on GitHub