Buttons & actions
Button
stableButtons trigger an action or a state change. Use them for the actions on a page and its surfaces — not for navigation.
Overview
Every button is one component with a variant that sets its emphasis. Give a view a single high-emphasis default button for its primary action, and drop to secondary, outline, or ghost for everything else so the hierarchy stays readable.
destructive signals an irreversible or dangerous action; link renders button behaviour with the appearance of a text link.
When to use
- →Trigger an immediate action — submit, save, confirm, delete.
- →Give a screen one obvious primary action (a single default button).
- →Offer lower-priority actions with secondary, outline, or ghost.
When not to use
- ✕Navigating to another page or URL — use a link so it's a real anchor.
- ✕Turning a setting on or off — use a Switch or Toggle.
- ✕Choosing among options — use a Toggle group, Radio group, or Select.
Variants
defaultPrimary action — one per view.secondaryA prominent but non-primary action.outlineLow-emphasis action on a busy surface.ghostMinimal action, e.g. in toolbars.destructiveIrreversible or dangerous action.destructiveOutlineDestructive intent, low emphasis — red at rest, solid red fill on hover.linkButton behaviour that looks like a link.size: sm | default | lg | iconicon = square, icon-only.
Do
- Lead labels with a verb — “Approve PO”, “Export ledger”.
- Keep one primary button per view — everything else lower-emphasis.
- Give icon-only buttons an aria-label — so their purpose is announced.
Don't
- Don't stack competing default buttons — the primary action stops being obvious.
- Don't use a button to navigate — that should be a link.
- Don't write vague labels — avoid “OK” / “Submit” when a verb fits.
Accessibility
- •Renders a native <button>: focusable and activated with Enter or Space.
- •Icon-only buttons must set aria-label (or visually-hidden text).
- •Focus is shown with the visible ring token — don't remove the outline.
- •Disabled buttons aren't focusable; never rely on colour alone to convey state.
- •For on/off buttons, set aria-pressed (see Button group / Toggle).
Code
Basic
import { Button } from "~/components/ui/button";
<Button>Approve PO</Button>
<Button variant="secondary">Save draft</Button>
<Button variant="destructive">Void invoice</Button>Sizes
<Button size="sm">Filter</Button>
<Button size="default">Approve PO</Button>
<Button size="lg">Approve & post</Button>Icon only
<Button size="icon" aria-label="Edit entry">
<PencilIcon />
</Button>Related
Icon buttonSplit buttonButton groupToggle
More examples
Variants
Variant × size
Sizes
Leading icon
Trailing icon
Icon only
Loading per variant
Disabled
Full width
Split button
Last action: —
Split variants
Icon button — variants
Icon button — sizes
FAB
Extended FAB
Button group
Viewing cash flow grouped by: Week
Group with icons
Toggle
Overdue-only filter: off
Single-select
Chart type: bars
Multi-select
Active marks: bold