Skip to content
Navigation

Action hierarchy

Every surface has exactly one obvious next step, every flow exactly one CTA. Rank everything else below.

What is a surface?

The unit the one-primary rule applies to: a card, a dialog, a form, a self-contained section. Not the page — a page composes many surfaces, so a card grid legitimately shows one default button per card. Within one surface there is never a second default.

Rules

  1. One primary (variant="default") per surface. When a second action appears, demote it to outline/secondary — even conditionally (e.g. a campaign card flips its action to outline the moment a “Pay” primary shows up next to it).
  2. size="cta" is the journey’s forward action — advance the step, create the first entity, pay. At most one visible per screen; screens outside the main flow usually have none.
  3. In a multi-step flow the CTA lives in one persistent action bar (e.g. a fixed bottom bar — ghost icon Back on the left, CTA on the right). Individual screens don’t grow their own competing primary; even form submission is delegated to the bar.
  4. Everything else demotes: stand-alone neutral actions → secondary; contextual utility/reset → outline; dismiss/close/toolbar → ghost.
  5. Destructive actions require confirmation only when irreversible or costly — deleting persisted work, discarding unsaved changes, moving money. Recoverable, in-flow removals (remove from cart, remove a re-uploadable file) execute immediately; a confirm dialog there is friction, not safety.
  6. Gate, don’t hide. An unavailable primary stays visible and disabled, with the reason shown (tooltip listing blockers, readiness checklist). [research]

Placement

  • Dialog / form footer — primary last in reading direction (right in LTR), cancel directly before it. [research]
  • Cancel variant — outline in dialog footers, ghost in lightweight inline confirmations; never default, never destructive. (Existing code predates this rule and is inconsistent — follow the rule, don’t copy the code.)
  • Cards — actions sit at the bottom of the card body, aligned left (start) with the content, primary first in reading order (the demoted action follows it); they stack vertically on narrow widths. Unlike dialog footers, nothing is pushed right — a card reads top-to-bottom and its action is part of that flow.
  • Inline edit idiom — pencil trigger → input + ButtonGroup of two outline icon-sm buttons, confirm (✓) first, cancel (✕) second; Enter confirms, Escape cancels.
  • Collections — the collection’s primary action (“New campaign”) lives in the view’s persistent chrome (sidebar, list header) or in the empty state — never repeated per item.
  • Empty state — guidance text plus the single CTA; never a wall of zeros.

Copy

What action labels and confirmations say — voice, sentence case, verb + object, error wording — lives in docs/patterns/copy.md.