components
Installation
SKILL.md
components
A component is a contract: it looks the same everywhere, behaves the same everywhere, and does not need to be looked at to be trusted. Most generated components fail the third part.
Primitive or hand-rolled?
Hand-roll only what has no behaviour: a card, a badge, a divider, a stat. Anything with focus management, keyboard interaction, positioning or ARIA uses a headless primitive.
| Need | Primitive | Why not hand-roll |
|---|---|---|
| Dialog, sheet, popover, menu, select, tooltip, tabs, toggle, slider, combobox | Base UI, Radix, React Aria, Ark | focus trap, escape, outside click, typeahead, ARIA, portal, collision |
| Drawer with drag | Vaul | gesture physics, snap points, scroll locking |
| Toast | Sonner | stacking, swipe, timers, a11y announcements |
| Command palette | cmdk | filtering, keyboard, groups, a11y |
| Animated numbers | NumberFlow | digit columns, locale formatting |
| Data table | TanStack Table (headless) | sorting, virtualisation, column state |
| Forms | native + a small validation lib | constraint API, focus on first error |
The rule: if it has a spec in ARIA Authoring Practices, use a primitive that implements it.