Components
Button
Full support Supported since v125. Full support Supported since v128. Full support Supported since v18.
Variants
Change the button variant with the .ui-outlined, .ui-tonal, and .ui-filled classes.
<div class="example-row"> <button class="ui-button">Text</button> <button class="ui-button" disabled>Disabled</button> <a class="ui-button" href="#">Link</a></div><div class="example-row"> <button class="ui-button ui-outlined">Outlined</button> <button class="ui-button ui-outlined" disabled>Disabled</button> <a class="ui-button ui-outlined" href="#">Link</a></div><div class="example-row"> <button class="ui-button ui-tonal">Tonal</button> <button class="ui-button ui-tonal" disabled>Disabled</button> <a class="ui-button ui-tonal" href="#">Link</a></div><div class="example-row"> <button class="ui-button ui-filled">Filled</button> <button class="ui-button ui-filled" disabled>Disabled</button> <a class="ui-button ui-filled" href="#">Link</a></div>Colors
Add a .ui-primary or .ui-critical class to apply
a brand or destructive color. The default is a neutral gray.
<div class="example-row"> <button class="ui-button ui-primary">Primary</button> <button class="ui-button ui-primary ui-outlined">Outlined</button> <button class="ui-button ui-primary ui-tonal">Tonal</button> <button class="ui-button ui-primary ui-filled">Filled</button></div><div class="example-row"> <button class="ui-button ui-critical">Critical</button> <button class="ui-button ui-critical ui-outlined">Outlined</button> <button class="ui-button ui-critical ui-tonal">Tonal</button> <button class="ui-button ui-critical ui-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="ui-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="ui-button ui-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="ui-button ui-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="ui-button ui-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="ui-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="ui-button ui-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="ui-button ui-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="ui-button ui-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="ui-button">Search <kbd>⌘K</kbd></button><button class="ui-button ui-outlined">Save <kbd>⌘S</kbd></button><button class="ui-button ui-tonal">Copy <kbd>⌘C</kbd></button><button class="ui-button ui-filled">Delete <kbd>⌘⌫</kbd></button>Icon-only
See Icon button documentation.
Sizes
Resize any button with the .ui-small and .ui-large
classes.
<div class="example-row"> <button class="ui-button ui-small">Small</button> <button class="ui-button">Default</button> <button class="ui-button ui-large">Large</button></div>
<div class="example-row"> <button class="ui-button ui-filled ui-small">Small</button> <button class="ui-button ui-filled">Default</button> <button class="ui-button ui-filled ui-large">Large</button></div>
<div class="example-row"> <button class="ui-button ui-outlined ui-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="ui-button ui-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="ui-button ui-outlined ui-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 .ui-disabled class.
<div class="example-row"> <button class="ui-button" disabled>Text</button>
<button class="ui-button ui-outlined" disabled>Outlined</button>
<button class="ui-button ui-tonal" disabled>Tonal</button>
<button class="ui-button ui-filled" disabled>Filled</button></div>
<div class="example-row"> <button class="ui-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="ui-button ui-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="ui-button ui-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="ui-button ui-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
- Container
- Label text (optional)
- Icon (optional)
API
| Type | Modifiers | Default | Description |
|---|---|---|---|
| Sizes | .ui-small, default, .ui-large | - | The size of the element. |
| Variants | default, .ui-outlined, .ui-tonal, .ui-filled | - | The variant to use. |
| Colors | .ui-critical, .ui-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(.ui-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 0.1s ease, color 0.1s ease, border-color 0.1s ease, box-shadow 0.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. */ &.ui-critical, &.ui-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); }
&.ui-critical { --_color: var(--critical); }
&.ui-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), &.ui-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. */ &.ui-x-small { --_min-height: var(--button-size-x-small); --_font-size: var(--font-size-0); padding-block: 0; padding-inline: 0.5ex; }
&.ui-small { --_min-height: var(--button-size-small); --_font-size: var(--font-size-05); padding-block: 0; padding-inline: 0.75ex; }
&.ui-large { --_min-height: var(--button-size-large); padding-inline: 4ex; }
/* Variants */ &.ui-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); } } }
&.ui-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); } } }
&.ui-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); }}