Button

Triggers actions. Six variants, four sizes, one disabled state.

Variant
Size
Label
State

Variants

Primary

Use it when there's one clear next step: continue a lesson, confirm an answer, unlock the next level. One Primary per screen, max.

Secondary

Use it when both actions carry equal weight and neither should recede. Think: 'Review answers' next to 'Submit test', where either choice matters.

Tertiary

Recedes alongside Primary or Danger so the dominant action wins. Works solo too, for low-stakes optional actions: 'See details', 'View badge history', 'Learn more'.

Ghost

Sits inside cards and dense layouts as a quiet inline action. Not for decision flows: use it for quick edits and secondary navigations within a view.

Danger

Warns before something irreversible happens: exits, resets, deletions. Always pair it with a Tertiary cancel and a confirmation step. Never let it fire on first tap.

Premium

Unlocks what's behind the paywall. Put it on upgrade screens and treat it like Primary: one per screen, never stacked alongside another Premium.

Disabled

Blocks an action until the student meets a condition. Always tell them what they need to do to unlock it. A disabled button with no explanation is a dead end.

Usage

One Primary per screen, maximum. It answers "what do I do next?" and everything else must recede around it. When two actions appear together, the second is almost always Tertiary (it disappears visually so Primary wins). Use Secondary only when both actions truly carry equal weight and neither should fade.

Ghost is not a two-action variant. It lives inside cards, tables, and dense layouts as an inline action, not next to Primary in a decision flow. Premium replaces Primary on upgrade screens; treat it the same way (one per screen, paired with Ghost for "maybe later"). Danger always goes with a Tertiary cancel alongside it, and always requires a confirmation step before it fires.

When the outcome is navigation rather than an action, pass the href prop. The component renders an <a> tag automatically.

Combinations

Primary + Tertiary: the standard two-action flow. Primary leads, Tertiary recedes. Use for confirm/cancel, continue/go back, or any pair where one action should dominate.
Danger + Tertiary: destructive confirmation dialogs. Danger on the right drives the action; Tertiary cancel on the left stays out of the way.
Primary + Secondary: only when both actions carry equivalent weight and neither should recede. Use sparingly; most flows need one clear winner.
Premium + Ghost: upgrade screens. Premium drives the action; Ghost handles "maybe later" without giving it real weight.
Button + icon slot: use icon-left for action reinforcement, icon-right for directional cues. Avoid filling both slots at once.

Do's & Don'ts

Do

  • Use one primary button per screen. It anchors the user's next move.
  • Pair Primary or Danger with Tertiary by default. Tertiary recedes so the dominant action wins.
  • Write labels as verb + noun: "Start test", "Save progress", "Unlock module".
  • Match size to density: xl for full-page CTAs, sm/md for inline actions inside cards.
  • Use href for navigation when the result is a destination, not a triggered action.

Don't

  • Don't place two primary buttons on the same screen. One of them needs to step down.
  • Don't use Tertiary as the main action when a decision is required. Its low visual weight works for optional actions, not for choices the student has to make.
  • Don't use Ghost in two-action flows. It belongs inside dense layouts, not alongside Primary.
  • Don't use vague labels. "Click here", "Submit", or "OK" say nothing about what happens next.
  • Don't trigger danger without a confirmation step. Destructive actions need a checkpoint.
  • Don't repeat premium across multiple elements. Its impact depends on scarcity.

Related: Option Card (the selection component that a primary button confirms) · Progress Bar (tracks lesson progress above the button in quiz screens)