A button or a link that looks like one, in six variants and four sizes.
Example
import { Button } from "@elements/ui/button";
import { Icon } from "@elements/ui/icon";
<Button variant="primary" onclick={() => save(form)}>Save changes</Button>
<Button variant="ghost" icon label="Close"><Icon name="x" /></Button>
<Button href="/docs" variant="link">Read the docs</Button>
<Button variant="primary" loading={state.saving}>Save</Button>
Parts
| Part |
What it is |
.button |
The <button> or <a>. Usable without the template: class="button is-primary is-sm". |
.button-label |
Wraps the slot; hidden (not removed) while loading so the width holds. |
.button.is-xs / .is-round |
Extra-small size and fully rounded corners, usable without the template. |
.button-spinner |
The loading ring: a Spinner (.spinner) sized to the button, centered over the label. |
Attributes
| Attribute |
Type |
Default |
Description |
variant |
"primary" | "secondary" | "outline" | "ghost" | "link" | "danger" |
"outline" |
Visual intent. primary is the accent fill, danger is destructive, link is text. |
size |
"xs" | "sm" | "md" | "lg" |
"md" |
Height, padding and type size from the theme's control tokens. xs steps down from sm. |
icon |
boolean |
false |
Square, icon-only button in any size. Requires label. |
round |
boolean |
false |
Fully rounded corners: a pill, or a circle with icon. |
label |
string |
"" |
Accessible name (aria-label). Required with icon. |
href |
string |
"" |
Renders an <a> instead of a <button>. |
type |
"button" | "submit" | "reset" |
"button" |
The button's form behavior. Ignored with href. |
disabled |
boolean |
false |
Not interactive. A disabled link loses its href and leaves the tab order. |
focusableWhenDisabled |
boolean |
false |
A disabled button stays focusable and in the tab order (aria-disabled), so focus is not lost while it is disabled. |
loading |
boolean |
false |
Shows the Spinner ring, sized to the button, over the hidden label; the button never changes size. Sets aria-busy and ignores clicks while staying focusable. |
block |
boolean |
false |
Full width of its container. |
class |
string |
"" |
Extra classes on the element. |
attrs |
Record<string, string | number | boolean | undefined> |
{} |
Any other attributes for the element: id, name, value, form, title, aria-*, data-*. |
onclick |
(e: MouseEvent) => void |
() => {} |
Click handler. Not called while disabled or loading. |
Slots
| Slot |
Content |
default |
The label: text, an <Icon>, or both. Icons size from --icon-size. |
Keyboard
| Keys |
Action |
Enter |
Activates the button or follows the link. |
Space |
Activates a <button>. |
Data attributes
| Attribute |
Values |
On |
data-variant |
the variant |
root |
data-size |
"xs" | "sm" | "md" | "lg" |
root |
data-loading |
present while loading |
root |
data-disabled |
present while disabled |
root |
Accessibility
- Renders a native
<button> (type="button" by default) or <a>, so Enter, Space and form submission work without script.
- An icon-only button gets its name from label; the template warns in the console when it is missing.
- Loading sets aria-busy="true" and aria-disabled="true" but keeps focus on the button, so a keyboard user is not dropped to the top of the page mid-save.
- A disabled link gets aria-disabled="true", role="link", no href and tabindex="-1".
- focusableWhenDisabled keeps a disabled button focusable with aria-disabled="true"; clicks and keys do nothing.
- aria-labelledby and aria-describedby pass through attrs.
- aria-invalid="true" through attrs draws a danger border, and a danger focus ring, for a button that stands for a field with an error.
- A button that opens a dialog ends its label with an ellipsis ("Rename…"), as the APG asks.
See also