Button

Nine variants, each with a specific job. Six are solid color fills — primary (gold) for the committing action, secondary (silver-blue) for the alternative, tertiary (bronze) for third-priority actions, caution (warm amber) for review-then-proceed warnings, critical (red) for destructive, irreversible actions, affirm (green) for confirming positive outcomes. Three are chrome utilities — ghost (flat gold text for Sign in), bare (neutral utility icon), ambient (a floating circle on the overlay plane). Buttons sit on the page like chips of solid color — white type on a filled surface, no glass, no metal, anywhere.

These buttons don't shimmer. The hover shimmer is the proposed system's move. Official buttons answer your pointer with motion instead: hover lifts the button 1px and deepens its fill; press scales it down to 0.97. The feedback is the fun — quick, physical, and out of your way before you notice it.

Variants

primary
The committing action — Send, Save, Sign in (form submit).
secondary
Solid silver-blue — Cancel, Reset, alternatives to the gold action.
tertiary
Solid bronze — third-priority actions in dense surfaces.
caution
Warm amber — review-then-proceed warnings. You pause, then you go.
critical
Solid red — destructive, irreversible actions. Delete, purge.
affirm
Solid green — confirming a positive outcome. Approve, accept.
ghost
Text-style entry — Sign in (chrome), Forgot?, link-like actions in conventional spots.
bare
Inline icon in a chrome bar — Site language, neutral icon controls.
ambient
Floating circle on the overlay plane — Preferences, Comms, Portal language.

Sizes

Two sizes — md is the default; sm for compact toolbars and inline density.

With icons

Filled variants require a leading icon by type. Optional trailing iconAfter. Ghost prohibits icons by type (text-style links don't take glyphs). Gap is a token (--space-2).

States

Hover lifts the button and deepens its fill; press scales it down; :focus-visible shows a 2px gold outline (keyboard-only, never on mouse click); disabled drops opacity to 0.45 and disables the pointer.

Collapsed

At collapsed width a filled button switches to its icon-only form — a circle holding just the glyph — but variant identity stays. A collapsed primary is still gold; a collapsed critical is still red. A circle, because there's no text left to carry. The collapsed prop is the explicit primitive; a future container-query trigger will fire automatically when horizontal space narrows. Ghost prohibits collapsing by type (text-style links have no icon to fall back to).

When collapsed, the button becomes icon-only — same accessible-name rule as ambient and bare: aria-label is required so screen readers still announce the action.

Paint-in / paint-out

Paint-in (disabled → enabled) keeps it simple here — the laser-engraver sweep belongs to the proposed system. An official button just fades up to full color over --dur-base — no sweep, no ceremony: it wakes up and gets to work. Paint-out (enabled → disabled) is just opacity fading to inert over --dur-quick — quietly out of the way; whatever caused the disable owns the attention. Buttons never use --dur-deliberate. Reduced-motion skips entirely.

When to use which

primary
One per surface. The committing action — Save, Send, Submit, Sign in (form). Solid gold draws the eye; use it sparingly.
secondary
The alternative to primary — Cancel, Reset, a non-committing alternative. Solid silver-blue. Can repeat per surface.
tertiary
Solid bronze. Third-priority actions in dense surfaces where primary and secondary are both already in use.
caution
Warm amber. Review-then-proceed warnings — the user should pause, but the action isn't destructive. Override, dismiss-with-consequences.
critical
Solid red. Destructive, irreversible actions — Delete, Purge, Revoke. Pair with a confirmation dialog.
affirm
Solid green. Confirms a positive outcome — Approve, Accept, Mark resolved.
ghost
Text-style action in a conventional spot — Sign in (chrome entry), Forgot?, secondary nav links. No outline because the position already carries the affordance.
bare
Inline icon control in a chrome bar — Site language, app-bar utility icons. No border or fill because the bar already contains it.
ambient
Floating circle on the overlay plane — Preferences (BL), Comms (BR), Portal language (TR). Flat fill with a soft shadow — a circle, because it floats free.

Accessibility

  • Icon-only variants (ambient; bare when used without a label) must receive an aria-label — and the label should carry state when state matters (e.g., "Language: English", not just "Language").
  • Focus is keyboard-only (:focus-visible) and renders a 2px gold outline. Never use mouse-focus styling — it competes with hover.
  • Disabled buttons drop opacity and disable the pointer; the underlying element is still announced by screen readers as "dimmed" — never hide.
  • The animation is governed by --ease-mechanical at --dur-quick; reduced-motion disables the transition.

Usage

Filled variants: icon + label requiredtsx
import { Button } from '@halo-compliance/ui'

<Button variant="primary" icon={Send} onClick={save}>
  Save changes
</Button>
Ghost: text-only, icons prohibitedtsx
<Button variant="ghost" onClick={signIn}>Sign in</Button>
Bare / Ambient: icon-as-children, aria-label requiredtsx
<Button variant="bare" aria-label="Language: English">{LanguageGlyph}</Button>
<Button variant="ambient" aria-label="Preferences">{SlidersGlyph}</Button>
  • /card — Card.Footer is where buttons mount inside a card.
  • /comms, /preferences — the ambient variant powers the silver bottom corners.
  • /app-bar#account — the ghost variant powers the Sign in CTA.
  • /error-states — page/section ErrorState fallbacks use Button for their recovery affordances.