Button
A button is the thing a person clicks to make something happen. button() renders a real <button> with type="button", so dropping one inside a form does not submit it by accident.
Basic button
The default is a solid, primary, medium button. Children are the label; anything else is a prop.
stack({ direction: 'row', gap: 'md' },
button('One'),
button('Two'),
button('Three'),
)Variants
Five levels of emphasis, from the one call to action on the page down to something that reads as a link.
stack({ direction: 'row', gap: 'md', wrap: true },
button({ variant: 'solid' }, 'Solid'),
button({ variant: 'soft' }, 'Soft'),
button({ variant: 'outline' }, 'Outline'),
button({ variant: 'ghost' }, 'Ghost'),
button({ variant: 'link' }, 'Link'),
)Colors
Every themed component draws from the same five palettes, so a color: 'danger' button and a color: 'danger' alert agree without either of them knowing about the other.
stack({ direction: 'row', gap: 'md', wrap: true },
button({ color: 'primary' }, 'Primary'),
button({ color: 'neutral' }, 'Neutral'),
button({ color: 'success' }, 'Success'),
button({ color: 'warning' }, 'Warning'),
button({ color: 'danger' }, 'Danger'),
)stack({ direction: 'row', gap: 'md', wrap: true },
button({ variant: 'soft', color: 'primary' }, 'Primary'),
button({ variant: 'soft', color: 'neutral' }, 'Neutral'),
button({ variant: 'soft', color: 'success' }, 'Success'),
button({ variant: 'soft', color: 'warning' }, 'Warning'),
button({ variant: 'soft', color: 'danger' }, 'Danger'),
)Sizes
stack({ direction: 'row', gap: 'md', align: 'center', wrap: true },
button({ size: 'sm' }, 'Small'),
button({ size: 'md' }, 'Medium'),
button({ size: 'lg' }, 'Large'),
)Icons
Pass any SVG markup as startIcon or endIcon. Icons are sized in em, so they scale with the button rather than needing a size of their own.
stack({ direction: 'row', gap: 'md', wrap: true },
button({
startIcon: icon('plus'),
}, 'New page'),
button({
variant: 'outline',
endIcon: icon('arrow-right'),
}, 'Continue'),
)Icon button
iconButton() is a square button holding a single icon. Its label is required — it becomes the accessible name that the icon itself cannot provide, and the tooltip on hover.
stack({ direction: 'row', gap: 'md' },
iconButton({ label: 'Add', icon: icon('plus') }),
iconButton({ label: 'Edit', variant: 'soft', icon: icon('edit') }),
iconButton({ label: 'Delete', variant: 'ghost', color: 'danger', icon: icon('trash') }),
)Loading and disabled
loading swaps in a spinner and sets aria-busy, leaving the label in place so the button does not change width mid-action.
stack({ direction: 'row', gap: 'md', wrap: true },
button({ loading: true }, 'Saving'),
button({ variant: 'outline', loading: true }, 'Checking'),
button({ disabled: true }, 'Disabled'),
button({ variant: 'soft', disabled: true }, 'Disabled'),
)Links
Give a button an href and it renders an <a> instead — the right element for something that navigates. Anchors have no disabled state, so disabled becomes aria-disabled and removes it from the tab order.
stack({ direction: 'row', gap: 'md', wrap: true },
button({ href: '/docs' }, 'Read the docs'),
button({ href: '/docs/ui', variant: 'outline' }, 'Components'),
button({ href: '/docs', variant: 'link' }, 'Plain link'),
)Full width
button({ block: true, size: 'lg' }, 'Deploy site')Props
Anything not listed here falls through to the rendered element as an attribute — id, data-*, onclick, popovertarget and the rest.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'solid' | 'soft' | 'outline' | 'ghost' | 'link' | 'solid' | How much emphasis the button carries. |
color | 'primary' | 'neutral' | 'success' | 'warning' | 'danger' | 'primary' | Which palette to draw from. |
size | 'sm' | 'md' | 'lg' | 'md' | Height, padding and label size. |
href | string | — | Renders an <a> instead of a <button>. |
startIcon | string | — | Markup placed before the label. |
endIcon | string | — | Markup placed after the label. |
loading | boolean | false | Shows a spinner and sets aria-busy. |
disabled | boolean | false | Disables the button, or marks a link aria-disabled. |
block | boolean | false | Stretches to the full width of its container. |
type | 'button' | 'submit' | 'reset' | 'button' | Only for the <button> form. |
iconButton() takes the same props plus a required label and an icon.