Skip to content

Button

The primary action control. Renders a <button>, or an <a> when given href. Orange darkens on hover/press β€” no scale, no bounce.

As link
import Button from '@repo/ui/Button';
<Button variant="primary" onClick={submit}>Submit order</Button>
<Button variant="primary" patch>Get started</Button> // patch corner β€” brand moment
<Button href="/inbox" variant="outline">Open inbox</Button>
PropTypeDefaultNotes
variantprimary | secondary | outline | ghost | destructiveprimaryprimary is the only orange one β€” keep it to ~one per view
sizesm | md | lgmd32 / 40 / 48px tall
patchbooleanfalseAsymmetric patch corner (8px 8px 8px 0). Reserve for brand moments
hrefstringβ€”Renders an <a> instead of <button>
className / classstringβ€”Merged via tailwind-merge

Plus all native <button> / <a> attributes (onClick, disabled, type, aria-*, …).

All states are token-driven: default β†’ hover (--om-orange-hover) β†’ active (--om-orange-press) β†’ :focus-visible (orange ring) β†’ disabled (50% opacity, no pointer).

  • Do use one primary per view β€” orange is ~2% of the layout.
  • Do use patch sparingly for hero CTAs.
  • Don’t add scale/bounce on hover, or use orange for secondary actions.
  • Don’t put body-length text in a button; it’s an action, sentence case, no ”!”.
  • Keyboard-operable as a native button/link; visible :focus-visible ring.
  • Icon-only buttons must pass an aria-label.
  • Verified with jest-axe (zero violations). Contrast note: orange-on-white is ~2.3:1; outline/ghost rings use --om-orange-press for β‰₯3:1 on light. See DECISIONS.md.