Button
StableA pill that starts an action. The primary pill carries Orbit's comet: light that passes once around it on hover and stays in orbit while the action runs.
Playground
Change the props and watch the pill. Hover the primary to send the comet round; turn on loading to keep it in orbit.
<Button variant="primary">Save changes</Button>Variants
Six materials, one shape. secondary is the default. Use primary once per view, for the action the page exists for.
When to use each
| Variant | Use it for |
|---|---|
primary | The one action the view exists for: Save, Create order, Publish. Hover sends the comet round once. |
secondary | Everything else that matters. The default. |
soft | Quiet actions that repeat down a page or sit in a toolbar. |
ghost | Cancel, dismiss, and actions beside a primary that should not compete with it. |
inverse | A strong call on a busy or photographic surface, where teal would clash. |
critical | Actions that destroy something. Confirm first with a ConfirmDialog. |
In both themes
Every variant, light and dark side by side. In dark, primary turns mint and its label turns ink.
Sizes
Heights snap to the control scale shared by every control in the kit, so a button, a search field and a segmented control line up in any toolbar: xs 24px, sm 30px, md 36px (default), lg 44px.
lgfor a page's single call to action and for touch-first screens.mdin forms, dialogs and page headers.smin the top bar, table toolbars and cards.xsinside dense rows only, never as a page's main action.
With icons
icon leads, iconEnd trails. A trailing caret means the button opens a menu; a trailing arrow-out means it leaves Orbit. Icons are 16px in md and scale with the size.
For a button that is only an icon, use Icon button: it requires a label.
Loading
While the action runs, the comet stays in orbit around the pill and the leading icon becomes an Orbit spinner. The button keeps focus and ignores repeat presses. Press it to see.
Disabled
Use sparingly. A disabled button does not say why, so prefer leaving it enabled and explaining the problem when it is pressed. When you must disable, say why nearby.
As a link
When the button goes somewhere rather than doing something, render the link itself with asChild. It keeps the link's semantics (open in new tab, copy address) and the pill's look.
Full width
Fills its container. For narrow panels, sheets on phones and the foot of a card.
Guidelines
- Sentence case, a verb first, two or three words: "Create order", "Save changes", "Send invoice".
- Keep an action's name through the flow: a "Publish" button leads to a "Published" message, not "Saved".
- Order pairs with the primary last (on the right), and the way out before it.
- Never put two buttons with the same label on one screen.
Accessibility
- Renders a native
buttonwithtype="button", so it never submits a form by accident. Passtype="submit"when it should. - The focus ring is teal, 2px, offset from the pill, and shows for keyboard focus only.
- The comet respects reduced motion: it holds still as a lit arc instead of travelling.
- Icons inside are hidden from assistive tech; the label names the button.
Props
Also accepts every native button attribute.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'soft' | 'ghost' | 'inverse' | 'critical' | 'secondary' | The pill's material. One primary per view. |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | Height from the control scale: 24, 30, 36 or 44px. |
icon | ReactNode | None | Leading icon. Replaced by a spinner while loading. |
iconEnd | ReactNode | None | Trailing icon, e.g. a caret for a menu. |
loading | boolean | false | Keeps the comet in orbit, shows a spinner and ignores presses, without dropping focus. |
fullWidth | boolean | false | Stretch to the container. |
asChild | boolean | false | Render the child element (a link) with button styling. |
disabled | boolean | false | Native disabled. Prefer explaining over disabling. |