Context
Components built without specs drift during implementation — one developer adds padding via props, another uses className overrides, a third hardcodes colors. This skill produces the contract that keeps the component library consistent, accessible, and composable.
Procedure
- Inventory every unique UI element from the section pattern library: buttons, cards, inputs, badges, avatars, navigation items, modals, tooltips, accordions, tabs.
- For each component, define the prop interface: required props (children, label), optional props (variant, size, disabled), and event handlers (onClick, onChange).
- Define variants for each component: visual styles (primary, secondary, ghost, destructive) and sizes (sm, md, lg).
- Write the accessibility spec: ARIA roles, keyboard interactions, focus management, screen reader announcements.
- Define responsive behavior: which props change at breakpoints, which variants are mobile-specific.
- Specify composition rules: which components can nest inside which, and forbidden combinations.
Output Format
# Component Build Specification
## Button
### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| children | ReactNode | required | Button label content |
| variant | 'primary' ∣ 'secondary' ∣ 'ghost' ∣ 'destructive' | 'primary' | Visual style |
| size | 'sm' ∣ 'md' ∣ 'lg' | 'md' | Size preset |
| disabled | boolean | false | Disable interaction |
| loading | boolean | false | Show spinner, disable click |
| asChild | boolean | false | Render as child element (Radix) |
### Sizes
| Size | Height | Padding | Font Size |
|------|--------|---------|-----------|
| sm | 32px | 12px 16px | 14px |
| md | 40px | 12px 20px | 14px |
| lg | 48px | 16px 24px | 16px |
### Accessibility
- Role: `button` (native)
- Keyboard: Enter/Space to activate
- Focus: visible focus ring (2px offset)
- Loading: `aria-busy="true"`, disable click
- Icon-only: require `aria-label`
---
## Card
### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| children | ReactNode | required | Card content |
| variant | 'default' ∣ 'outlined' ∣ 'elevated' | 'default' | Visual treatment |
| interactive | boolean | false | Add hover state |
| as | 'div' ∣ 'article' ∣ 'a' | 'div' | HTML element |
### Accessibility
- Semantic: `<article>` when self-contained content
- Interactive: focus ring when clickable, role="link" or role="button"
- Images inside: require alt text
---
## [Additional components follow same pattern]
## Composition Rules
| Parent | Allowed Children | Forbidden |
|--------|-----------------|-----------|
| Card | Badge, Button, Text, Image | Card (no nesting) |
| Modal | Any | Modal (no nesting) |
| Nav | NavItem, Button | Form elements |
QA Rubric (scored)
- API clarity (0-5): props are self-documenting without needing examples.
- Accessibility (0-5): every interactive component has keyboard, focus, and ARIA specs.
- Variant coverage (0-5): all common visual variations are defined as named variants.
- Composition safety (0-5): forbidden combinations are documented to prevent layout bugs.
Examples (good/bad)
- Good: "Button has 4 variants (primary, secondary, ghost, destructive), 3 sizes, loading state with aria-busy, and asChild for Radix composition. Default: primary/md — renders a usable button with zero configuration."
- Bad: "Button component — accepts className, style, and any HTML attribute. Style it however you want." — no contract, no consistency.
Variants
- Headless mode: spec defines behavior and accessibility only — no visual styling (for teams using their own CSS).
- Figma-linked mode: each component spec includes the Figma component URL for direct design-to-code traceability.