Design System
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.

VariantWhen to use
defaultThe one main action per view.
secondary / outline / ghostSupporting actions, in descending emphasis.
destructiveIrreversible actions — pair with a confirmation Modal.
linkInline navigation styled as text (teal, AA on light).
gradientBrand 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.

PropertyValue
Height40px default · 32px sm · 44px lg · square icon sizes
Typography14px / Inter 600 (13px sm, 15px lg)
Radius--radius-md (6px)
Primary fill--primary with --primary-foreground ink text
Focus2px --ring, offset 2px
Disabled50% 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 destructive for 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 gradient variant in dense UI — it is a hero CTA, one per view.
  • Use link variant 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; use asChild to render a Link that looks like a button.
  • Icon-only buttons require aria-label.
  • Focus ring is 2px --ring with offset — never removed.
  • Keyboard: Enter or Space activates; Tab moves focus.

Props

Button also accepts every native <button> attribute.

PropTypeDefaultDescription
asChildboolean | undefinedfalseRender 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

On this page