Decide how to structure a UI unit before writing it, so the choices your audits would otherwise catch late (accessibility, i18n, bundle cost, missing states) are made up front. This is the frontend counterpart to codebase-design: treat a component as a deep module — a lot of behaviour behind a small prop surface.
It is a knowledge/decision skill, not a code generator. It resolves the design questions, then hands the actual implementation to tdd/build and verification to the audit skills. Framework-agnostic; examples in React.
Boundaries:
- vs
tdd/build— they implement; this decides the UI shape and hands off. - vs
codebase-design— that is generic module depth; this applies the lens to components (prop surface = public API). - vs
prototype— that explores throwaway directions; this is for code that stays. - vs
a11y-audit/i18n/perf-audit/visual-validate— they verify after; this builds it right up front. It references their standards, never re-copies their checklists.
Workflow
Phase 1 — Classify the work
Name the unit and pick the emphasis:
| Kind | Emphasis |
|---|---|
| Design-system primitive (Button, Input) | prop API, variants via props, tokens, a11y contract |
| Composite component | composition, state placement, the required states |
| Page / route | data fetching boundary, layout, loading/error at the route |
| Refactor of existing UI | shrink prop surface, extract states, remove magic values |
Phase 2 — Decision pass (resolve before coding)
Work through each; state the decision explicitly.
- Boundary & prop API. Smallest surface that serves callers. Prefer composition (
children/slots) over configuration. A growing set of boolean flags (isPrimary,isSmall,isLoading…) is a smell — reach for avariant/sizeunion or composition instead. - Where state lives. The lowest owner that still works: local → lifted to parent → server state → URL. No derived state stored twice; compute from source.
- Data & async. Decide where data is fetched (route/loader boundary vs. inside the component) and who owns caching. Keep components that render data separate from components that fetch it where practical.
- Required UI states. Enumerate and design them now, not later: loading, empty, error, disabled, and partial/optimistic where relevant. A component that only handles the happy path is unfinished.
- Styling. Use design-system tokens (no magic colors/spacing). Express variants through props, not one-off class overrides.
- Responsive / adaptive. Mobile-first; intentional breakpoints; no fixed widths that break small screens.
- Accessibility by construction. Semantic HTML first, ARIA only as a last resort; keyboard + focus order; a label for every control; visible focus. (Defers to
a11y-auditfor the full WCAG pass.) - User-facing strings. Route them through the project's i18n path from the start rather than hardcoding. (Defers to
i18n.)
Phase 3 — Build
Apply the decisions. Keep the component shallow at its interface and hide implementation detail behind it. Delegate any non-trivial logic to tdd (red → green → refactor); this skill does not hand-write the whole component or its tests.
Phase 4 — Definition of done + handoff
Do not consider the unit done until:
- Prop surface is minimal; no boolean-flag proliferation
- Loading, empty, error, and disabled states exist
- Keyboard reachable and operable; semantic elements used
- Styling uses tokens; responsive down to the smallest target
- User-facing strings are translatable
Then hand off: tdd for behavior tests (query by role/label), visual-validate for before/after in a real browser, and let review run the audits (a11y/i18n/perf) as the final gate.
Rules
- Resolve the Phase 2 decisions explicitly before writing the component — state each choice.
- Reference the audit skills' standards; never duplicate their checklists here.
- Never hand-write full tests — that is
tdd. This skill designs; it does not replace the builders. - Framework-agnostic; do not assume a specific framework unless the codebase already uses one.
- Stay within the current unit — do not redesign unrelated components.
Anti-rationalization
Excuses that skip the work, and the rebuttal:
| Excuse | Rebuttal |
|---|---|
| "I'll add the error/empty state later." | Later never comes and it ships half-built. States are part of the design pass, not a follow-up. |
| "A boolean prop is faster right now." | Three booleans is eight states, most untested. A variant union or composition is cheaper within a week. |
| "Hardcode the string, I'll translate later." | Retro-i18n means re-touching every component. Route it now — it's one import. |
| "ARIA will fix the accessibility." | Semantic HTML gives it for free; ARIA is the patch for when you couldn't. Reach for the element first. |
| "Fetch inside the component, it's simpler." | It couples render to network and blocks reuse/testing. Decide the fetch boundary deliberately. |
Red flags
- A prop list longer than the component's own logic.
any/loose props at the component boundary.- Only the happy path rendered.
- Magic color/spacing values instead of tokens.
div/spanwith click handlers instead of abutton/a.