Skip to main content

Theme config

Theme mode

Color palette

Grays

Border radii/radiuses/radiopedes/you know
Border radius
Field border radius
Button border radius
All
Components
Guides
API
Recent

Components

Button

Buttons allow users to take actions, and make choices, with a single tap.

Full support Supported since v125. Full support Supported since v128. Full support Supported since v18.

Variants

Change the button variant with the .outlined, .tonal, and .filled classes.

Link
Link
Link
Link
<div class="example-row">
<button class="button">Text</button>
<button class="button" disabled>Disabled</button>
<a class="button" href="#">Link</a>
</div>
<div class="example-row">
<button class="button outlined">Outlined</button>
<button class="button outlined" disabled>Disabled</button>
<a class="button outlined" href="#">Link</a>
</div>
<div class="example-row">
<button class="button tonal">Tonal</button>
<button class="button tonal" disabled>Disabled</button>
<a class="button tonal" href="#">Link</a>
</div>
<div class="example-row">
<button class="button filled">Filled</button>
<button class="button filled" disabled>Disabled</button>
<a class="button filled" href="#">Link</a>
</div>

Colors

Add a .primary or .critical class to apply a brand or destructive color. The default is a neutral gray.

<div class="example-row">
<button class="button primary">Primary</button>
<button class="button primary outlined">Outlined</button>
<button class="button primary tonal">Tonal</button>
<button class="button primary filled">Filled</button>
</div>
<div class="example-row">
<button class="button critical">Critical</button>
<button class="button critical outlined">Outlined</button>
<button class="button critical tonal">Tonal</button>
<button class="button critical filled">Filled</button>
</div>

Buttons with icon and label

Include an icon alongside text by nesting an SVG element within the button.

<div class="example-row">
<button class="button">
Text
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
<button class="button outlined">
Outlined
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
<button class="button tonal">
Tonal
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
<button class="button filled">
Filled
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
</div>
<div class="example-row">
<button class="button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
Text
</button>
<button class="button outlined">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
Outlined
</button>
<button class="button tonal">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
Tonal
</button>
<button class="button filled">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
Filled
</button>
</div>

Keyboard

Use the <kbd> element to provide keyboard hints within a button.

<button class="button">Search <kbd>⌘K</kbd></button>
<button class="button outlined">Save <kbd>⌘S</kbd></button>
<button class="button tonal">Copy <kbd>⌘C</kbd></button>
<button class="button filled">Delete <kbd>⌘⌫</kbd></button>

Icon-only

See Icon button documentation.

Sizes

Resize any button with the .small and .large classes.

<div class="example-row">
<button class="button small">Small</button>
<button class="button">Default</button>
<button class="button large">Large</button>
</div>
<div class="example-row">
<button class="button filled small">Small</button>
<button class="button filled">Default</button>
<button class="button filled large">Large</button>
</div>
<div class="example-row">
<button class="button outlined small">
Small
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
<button class="button outlined">
Default
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
<button class="button outlined large">
Large
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
</div>

Disabled

Add disabled styling with the disabled attribute or the .disabled class.

<div class="example-row">
<button class="button" disabled>
Text
</button>
<button class="button outlined" disabled>
Outlined
</button>
<button class="button tonal" disabled>
Tonal
</button>
<button class="button filled" disabled>
Filled
</button>
</div>
<div class="example-row">
<button class="button" disabled>
Text
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
<button class="button outlined" disabled>
Outlined
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
<button class="button tonal" disabled>
Tonal
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
<button class="button filled" disabled>
Filled
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor"
d="M11.75 3a.75.75 0 0 1 .743.648l.007.102l.001 7.25h7.253a.75.75 0 0 1 .102 1.493l-.102.007h-7.253l.002 7.25a.75.75 0 0 1-1.493.101l-.007-.102l-.002-7.249H3.752a.75.75 0 0 1-.102-1.493L3.752 11h7.25L11 3.75a.75.75 0 0 1 .75-.75">
</path>
</svg>
</button>
</div>

File upload

Is it a button? Is it an input? You can find the docs for it here at least.

Anatomy

  1. Container
  2. Label text (optional)
  3. Icon (optional)

API

Type Modifiers Default Description
Sizes .small, default, .large - The size of the element.
Variants default, .outlined, .tonal, .filled - The variant to use.
Colors .critical, .primary - Color modifiers. Default is a neutral gray.

Browser support

Full support Supported since v125. Full support Supported since v128. Full support Supported since v18.

See also the full browser support guide.

Installation

@layer components.root {
:where(.button) {
--_color: light-dark(var(--color-16), var(--color-1));
--_color-contrast: light-dark(var(--color-1), var(--color-16));
--_color-tonal: var(--surface-tonal);
--_accent: var(--_color);
--_accent-contrast: var(--_color-contrast);
--_accent-tonal: var(--_color-tonal);
--_accent-tonal-contrast: var(--_color);
--_default-hover-bg-color: light-dark(oklch(from var(--_accent) l 0.01 h / 10%),
oklch(from var(--_accent) l 0.01 h / 20%));
--_default-active-bg-color: light-dark(oklch(from var(--_accent) l 0.06 h / 20%),
oklch(from var(--_accent) l 0.06 h / 30%));
--_filled-hover-bg-color: light-dark(oklch(from var(--_accent) calc(l + 0.2) c h),
oklch(from var(--_accent) calc(l - 0.1) c h));
--_filled-active-bg-color: light-dark(oklch(from var(--_accent) calc(l + 0.3) c h),
oklch(from var(--_accent) calc(l - 0.15) c h));
--_outlined-active-bg-color: var(--_filled-active-bg-color);
--_bg-color: transparent;
--_border-color: transparent;
--_border-width: var(--border-size-1);
--_font-size: var(--font-size-1);
--_min-height: var(--button-size);
--_border-radius: var(--button-border-radius, var(--radius-2));
--_text-color: var(--_accent);
-webkit-tap-highlight-color: transparent;
-webkit-touch-callout: none;
align-items: center;
background-color: var(--_bg-color);
border: var(--_border-width) solid var(--_border-color);
border-radius: var(--_border-radius);
color: var(--_text-color);
display: inline-flex;
font-size: var(--_font-size);
font-weight: 700;
gap: var(--size-2);
justify-content: center;
min-block-size: var(--_min-height);
padding-block: 0.5ex;
padding-inline: 1.5ex;
text-align: center;
text-decoration: none;
transition: background-color .1s ease, color .1s ease,
border-color .1s ease, box-shadow .1s ease;
user-select: none;
/* Colors — shared interaction model for critical and primary.
Each color modifier below only swaps --_color; the tonal surface,
contrast text, and hover/active strategy are identical.
The .critical scope class in theme.css redirects --palette-source so
--color-6 below becomes a tint of the active color. */
&.critical,
&.primary {
--_color-contrast: var(--gray-1);
--_color-tonal: var(--color-6);
--_accent-tonal-contrast: var(--text-primary-contrast);
--_default-hover-bg-color: oklch(from var(--_accent) l c h / 15%);
--_default-active-bg-color: oklch(from var(--_accent) l c h / 25%);
--_filled-hover-bg-color: oklch(from var(--_accent) calc(l - 0.1) c h);
--_filled-active-bg-color: oklch(from var(--_accent) calc(l - 0.15) c h);
--_outlined-active-bg-color: oklch(from var(--_accent) calc(l - 0.1) c h);
}
&.critical {
--_color: var(--critical);
}
&.primary {
--_color: var(--primary);
}
/* Disabled */
&:where([disabled]) {
--_text-color: color-mix(in oklch,
var(--text-muted) 50%,
var(--surface-default));
cursor: not-allowed;
opacity: 0.64;
}
/* Hover & Active */
&:where(:not([disabled])) {
&:where(:not(:active):hover) {
--_bg-color: var(--_default-hover-bg-color);
}
&:where(:hover:active),
&[aria-current="page"] {
--_bg-color: var(--_default-active-bg-color);
}
}
/* Icons / Keyboard */
&:where(:has(svg), &.icon-only) {
gap: 1ex;
svg {
color: currentColor;
max-block-size: 0.7lh;
}
}
/* Keyboard input */
:is(kbd) {
background-color: oklch(from currentColor l c h / 10%);
border: 0;
color: oklch(from currentColor l c h / 80%);
font-size: 0.8em;
font-weight: 400;
line-height: 1.2;
}
/* Sizes — heights aliased from the shared --control-size scale.
Override --button-size-* in a parent scope to resize an entire region. */
&.x-small {
--_min-height: var(--button-size-x-small);
--_font-size: var(--font-size-0);
padding-block: 0;
padding-inline: .5ex;
}
&.small {
--_min-height: var(--button-size-small);
--_font-size: var(--font-size-05);
padding-block: 0;
padding-inline: .75ex;
}
&.large {
--_min-height: var(--button-size-large);
padding-inline: 4ex;
}
/* Variants */
&.outlined {
--_bg-color: transparent;
--_border-color: var(--_accent);
--_text-color: var(--_accent);
&:where(:not([disabled])) {
&:where(:not(:active):hover) {
--_bg-color: var(--_accent);
--_border-color: var(--_accent);
--_text-color: var(--_accent-contrast);
}
&:where(:active) {
--_bg-color: var(--_outlined-active-bg-color);
--_border-color: var(--_outlined-active-bg-color);
--_text-color: var(--_accent-contrast);
}
}
}
&.tonal {
--_bg-color: var(--_accent-tonal);
--_text-color: var(--_accent-tonal-contrast);
&:where(:not([disabled])) {
&:where(:not(:active):hover) {
--_bg-color: var(--_accent);
--_text-color: var(--_accent-contrast);
}
&:where(:active) {
--_bg-color: var(--_outlined-active-bg-color);
--_text-color: var(--_accent-contrast);
}
}
}
&.filled {
--_bg-color: var(--_accent);
--_text-color: var(--_accent-contrast);
&:where(:not([disabled])) {
&:where(:not(:active):hover) {
--_bg-color: var(--_filled-hover-bg-color);
}
&:where(:active) {
--_bg-color: var(--_filled-active-bg-color);
}
}
}
}
/* file input */
:where(input[type="file"]) {
align-self: flex-start;
border: var(--border-size-1) solid var(--surface-filled);
border-radius: var(--radius-2);
box-shadow: var(--inner-shadow-4);
color: var(--text-muted-contrast);
cursor: initial;
max-inline-size: 100%;
padding: 0;
}
:where(input[type="file"])::-webkit-file-upload-button,
:where(input[type="file"])::file-selector-button {
cursor: pointer;
margin-inline-end: var(--size-relative-6);
}
}