Buttons
Button
Trigger an action or navigation. Seven variants cover the hierarchy from the one primary action per view down to inline links and the hero-only gradient CTA.
Variants
Hierarchy, not decoration: pick by the action's importance.
| Variant | When to use |
|---|---|
default | The one main action per view. |
secondary / outline / ghost | Supporting actions, in descending emphasis. |
destructive | Irreversible actions — pair with a confirmation Modal. |
link | Inline navigation styled as text (teal, AA on light). |
gradient | Brand hero CTA only — never in dense product UI. |
Sizes & icon buttons
Three text sizes plus square icon-only sizes — icon buttons must carry an aria-label.
With icons
Pair a leading or trailing icon to reinforce meaning. A leading icon labels the action; a trailing arrow signals forward movement.
States
Disabled and pending. A pending button keeps its label so width does not jump.
Structure
The tokens behind the control.
| Property | Value |
|---|---|
| Height | 40px default · 32px sm · 44px lg · square icon sizes |
| Typography | 14px / Inter 600 (13px sm, 15px lg) |
| Radius | --radius-md (6px) |
| Primary fill | --primary with --primary-foreground ink text |
| Focus | 2px --ring, offset 2px |
| Disabled | 50% opacity, pointer events off |
Best practices
Do
- One primary button per view — it marks the single main action.
- Write labels as verb phrases: "Submit claim", not "OK" or "Submit".
- Use
destructivefor irreversible actions, and confirm them with a Modal. - Give icon-only buttons an
aria-label— always. - Show progress inside the button (Spinner + label) and disable it while pending.
Don't
- Use the
gradientvariant in dense UI — it is a hero CTA, one per view. - Use
linkvariant for actions that change data — links navigate, buttons act. - Stack more than three actions in a row; move the rest into a dropdown.
- Disable a button without explaining why (hint, tooltip or inline message).
Accessibility & keyboard
- Real
<button>semantics; useasChildto render a Link that looks like a button. - Icon-only buttons require
aria-label. - Focus ring is 2px
--ringwith offset — never removed. - Keyboard: Enter or Space activates; Tab moves focus.
Props
Button also accepts every native <button> attribute.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | undefined | false | Render as the child element via Radix `Slot` instead of a native `<button>` — e.g. to turn a link into a button. |
variant | "default" | "secondary" | "outline" | "ghost" | "destructive" | "link" | "gradient" | null | undefined | — | — |
size | "default" | "sm" | "lg" | "icon" | "icon-sm" | null | undefined | — | — |