Component docs
Button
Triggers an action. One primary button per view; everything else steps down.
When to use
- Use for actions that change data or open UI. Use a link for navigation.
- Keep labels short verbs: “Save changes”, not “Click here”.
- Use `loading` instead of disabling during async work so focus stays put.
Playground
Change props on the right; the preview and code update instantly.
<Button variant="primary" size="md">Save changes</Button>Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | primary | secondary | outline | ghost | destructive | primary | Visual emphasis. |
size | sm | md | lg | md | Scale. `sm` keeps a 44px hit area. |
loading | boolean | false | Shows a spinner, sets aria-busy and announces loadingLabel. |
loadingLabel | string | Loading, please wait | Text announced to screen readers while loading. |
fullWidth | boolean | false | Stretches to the container width. |
startIcon | ReactNode | — | Icon before the label (decorative). |
endIcon | ReactNode | — | Icon after the label (decorative). |
disabled | boolean | false | Native disabled state; removes from tab order. |
Keyboard navigation
| Keys | Behavior |
|---|---|
| Tab / Shift+Tab | Move focus to / from the button. |
| Enter | Activate. |
| Space | Activate (on key release). |
ARIA attributes
| Attribute | Guidance |
|---|---|
aria-label | Required on icon-only buttons. Describe the action, not the icon. |
aria-busy | Set automatically while `loading`; the polite live region announces loadingLabel. |
aria-pressed | Add only for toggle buttons, with true/false reflecting state. |
aria-expanded / aria-controls | Add when the button opens a menu or disclosure. |
Theme tokens
Every part of Button reads from these tokens, so it re-themes in light and dark automatically.
| Part | Tokens |
|---|---|
| Container (primary) | --primary--primary-hover--primary-active--shadow-xs |
| Container (secondary) | --secondary--secondary-hover--secondary-active |
| Container (outline / ghost) | --border-strong--muted--primary-subtle |
| Container (destructive) | --destructive--destructive-hover |
| Label | --primary-foreground--secondary-foreground--font-body--weight-semibold--text-sm--text-body--text-lg |
| Shape & spacing | --radius-md--space-2--space-3--space-5--border-width |
| Focus ring | --focus-ring--focus-ring-width--focus-ring-offset |
| Hit area & motion | --target-min--duration-fast--ease-standard--opacity-disabled |
Accessibility checklist
0 of 7 verified
Check contrast numbers live on the Accessibility page.