# Button
A button or a link that looks like one, in six variants and four sizes.
```ehtml Example
import { Button } from "@elements/ui/button";
import { Icon } from "@elements/ui/icon";
save(form)}>Save changes
Read the docs
Save
```
## Parts
| Part | What it is |
|---|---|
| `.button` | The `` or ``. 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 ` ` instead of a ``. |
| `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` | `{}` | 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 ``, or both. Icons size from --icon-size. |
## Keyboard
| Keys | Action |
|---|---|
| `Enter` | Activates the button or follows the link. |
| `Space` | Activates a ``. |
## 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 `` (type="button" by default) or ``, 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
- [Icon](icon): An inline stroke icon from the set the templates draw their own controls with, sized in pixels and colored by the text around it.
- [Dialog](dialog): A modal window over the page that traps focus until it closes.