Skip to content

<Component> — spec

Status: · Owner: · Last updated:

Purpose

<2 sentences. The user need this serves and the canonical context.>

Anatomy

<Component>
├── <Part1>
├── <Part2>
└── <Part3>
Part Purpose Required Default if omitted
<Part1> ... yes

API

Prop Type Default Description
value string Controlled value.
onChange (value: string) => void Fires on change.
size "sm" \| "md" \| "lg" "md"
disabled boolean false

States

State Trigger Visual
Default resting base
Hover mouse-over bg lighten 4%
Focus-visible keyboard tab 2px ring --color-focus-ring, offset 2px
Active press bg darken 6%
Disabled disabled opacity 0.5, no pointer-events
Loading loading content swapped for spinner

Variants

Size

Size Height Font Padding
sm 28px 13px 8px 12px
md 32px 14px 8px 16px
lg 40px 16px 12px 20px

Color (or "intent")

Value Use Background Text
primary primary CTA --color-primary-default --color-on-primary
secondary non-primary action --color-bg-elevated --color-text-primary
ghost low-emphasis action transparent --color-text-primary
danger destructive --color-error white

Tokens consumed

--color-primary-default
--color-primary-hover
--color-on-primary
--space-md
--radius-md
--transition-default
--color-focus-ring

Accessibility

  • Semantic element: <button type="button">. Never <div onClick>.
  • ARIA:
  • aria-label if no visible text.
  • aria-disabled="true" when disabled (in addition to native disabled).
  • aria-busy="true" when loading.
  • Keyboard: Enter and Space activate. Tab reaches.
  • Touch: minimum 44×44 hit area on mobile (use padding to extend if visual size is smaller).
  • Focus: 2px ring with 3:1 contrast against both element and adjacent background.

Code example

<Button
  size="md"
  intent="primary"
  onClick={handleSubmit}
  disabled={isPending}
  loading={isPending}
>
  Save changes
</Button>

Edge cases

  • Long text: truncates with if exceeds container; full text in title attribute.
  • Empty state: <Component> with no children renders nothing (does not crash, does not reserve space).
  • RTL: icon swap, padding mirror.
  • Reduced motion: omit fade transitions, keep instant state changes.
  • Print: hidden by default (@media print { display: none; }) unless explicitly requested.

Don't

  • Don't pass icons as children AND as icon prop.
  • Don't use intent="primary" for more than one button per surface.
  • Don't use loading and disabled simultaneously — pick one.

References