Button
The primary action control. Renders a <button>, or an <a> when given href. Orange darkens
on hover/press β no scale, no bounce.
import Button from '@repo/ui/Button';
<Button variant="primary" onClick={submit}>Submit order</Button><Button variant="primary" loading={isSubmitting}>Submittingβ¦</Button><Button variant="primary" patch>Get started</Button> // patch corner β brand moment<Button href="/inbox" variant="outline">Open inbox</Button>| Prop | Type | Default | Notes |
|---|---|---|---|
variant |
primary | secondary | outline | ghost | destructive |
primary |
primary is the only orange one β keep it to ~one per view |
size |
sm | md | lg |
md |
32 / 40 / 48px tall |
patch |
boolean |
false |
Asymmetric patch corner (8px 8px 8px 0). Reserve for brand moments |
loading |
boolean |
false |
Shows a leading <Spinner />, sets aria-busy, and auto-disables <button> |
href |
string |
β | Renders an <a> instead of <button> |
className / class |
string |
β | Merged via tailwind-merge |
Plus all native <button> / <a> attributes (onClick, disabled, type, aria-*, β¦).
All states are token-driven: default (--om-orange-cta) β hover (--om-orange-cta-hover) β active
(--om-orange-cta-press) β :focus-visible (--om-orange-press ring) β disabled / loading (50% opacity, no pointer).
Do / donβt
Section titled βDo / donβtβ- Do use one
primaryper view β orange is ~2% of the layout. - Do use
patchsparingly 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 β!β.
Accessibility
Section titled βAccessibilityβ- Keyboard-operable as a native button/link; visible
:focus-visiblering. - Icon-only buttons must pass an
aria-label. - Verified with
jest-axe(zero violations). Contrast note:primaryuses--om-orange-ctawith--om-fg-on-orangefor 4.91:1 WCAG AA contrast, andoutline/ghostfocus rings use--om-orange-pressfor β₯3:1 on light surfaces. See Color foundations.