Component Architecture
Turn a tangle of one-off components into a composable system: audit what exists, classify it into atomic levels, then refactor the worst offenders into small, typed, documented pieces. The prime directive: a component earns its existence by having one responsibility and a prop interface that makes invalid states unrepresentable. Deliver working refactored code plus an audit the user can act on — never just advice.
When to use / when not to
Use for: component decomposition, prop interface design, variant systems, extracting a shared library, deciding controlled vs uncontrolled, component documentation.
Hand off instead when the real need is:
- Visual tokens (spacing, color, type scales) →
skills/frontend-design/design-foundation
- Animation/feedback inside components →
skills/frontend-design/interaction-physics
- Keyboard/ARIA behavior of components →
skills/frontend-design/accessibility-excellence
- Render performance (memoization, re-renders) →
skills/frontend-design/performance-optimization
- Unsure where to start across the whole frontend →
skills/frontend-design/frontend-orchestrator
Step 0 — Inspect the codebase, then ask only what's left
Before proposing anything, build a component inventory from the actual code:
- Locate component directories (
components/, ui/, src/app/**, lib/). Note the framework and styling approach (Tailwind, CSS Modules, CSS-in-JS, vanilla) — match it; never introduce a new styling system uninvited.
- Count components and flag: files > ~200 lines, components that both fetch data and render detailed markup, duplicated UI (multiple button/input/card implementations), inline styles repeating the same values, class-based inheritance.
- Check for an existing design system or UI kit (shadcn/ui, MUI, Chakra, internal package). If one exists, extend its conventions — don't build a parallel system.
Ask the user (one batch, only what the code didn't answer): scope (whole app, one feature, or one painful component?) and whether a shared library/package is the goal or just cleaner local structure. If the request already implies scope ("refactor this file"), don't ask — state assumptions and proceed.
Workflow
1. Classify the inventory into atomic levels
- Atoms — indivisible, no component dependencies: Button, Input, Label, Icon, Badge, Spinner.
- Molecules — small compositions of atoms with one purpose: FormInput (Label+Input+Error), SearchBar.
- Organisms — sections with business purpose and often state: NavBar, Card, Modal, Form.
- Templates — page layouts arranging organisms; not reusable across page types.
- Pages — templates with real data; use them to find edge cases.
Decision rule: if you can't classify a component, it's doing too much — that's a refactor candidate, not a taxonomy problem.
2. Prioritize refactors by leverage
Order: (1) duplicated atoms (consolidate first — everything else builds on them), (2) god components violating single responsibility, (3) prop interfaces that allow invalid states, (4) missing variants forcing copy-paste. Propose the top 3–5 refactors with a one-line payoff each; have the user confirm scope before rewriting broadly. For a single-component request, skip the vote and refactor it.
3. Refactor with these decision rules
- Split rule: a component that fetches data, manages form state, AND renders detailed markup becomes an orchestrator plus focused children. Split by responsibility, not by line count.
- Composition over inheritance, always. Variants are props (
variant, size), presets are thin wrappers — never subclasses.
- Controlled vs uncontrolled: if any other UI must react to the value while editing (live validation, dependent fields, character counts) → controlled. Fire-and-forget input read once on submit → uncontrolled is fine. Never mix modes in one component.
- Prop interface rules: union types instead of booleans that can conflict (
variant: 'primary' | 'danger', not isPrimary + isDanger); constrain to valid options; pass through className and ARIA attributes; callbacks named on<Event>. If two boolean props can combine into an invalid state, redesign the interface.
- Extraction threshold: extract a shared component at the 2nd–3rd duplication if the copies are genuinely the same concept. Two things that look alike but change for different reasons stay separate — wrong abstractions cost more than duplication.
Canonical shape for an atom (full gallery in references/patterns.md):
interface ButtonProps {
variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
loading?: boolean;
onClick?: () => void;
children: React.ReactNode;
}
export const Button = ({ variant = 'primary', size = 'md', disabled, loading, ...rest }: ButtonProps) => (
<button
className={`button button--${variant} button--${size}`}
disabled={disabled || loading}
{...rest}
/>
);
4. Document what you build
Every extracted/refactored shared component gets docs: purpose, props table, variants with when-to-use, states, accessibility notes, edge cases. Use the template in references/patterns.md. Put docs where the team will see them (Storybook stories if Storybook exists, otherwise a colocated README.md or JSDoc).
Required output format
Deliver both artifacts:
1. The code — refactored/created component files, edited in place, following the project's existing styling and naming conventions. All call sites updated; the app must still compile.
2. Component Architecture Audit (markdown):
## Component Inventory
| Component | File | Level | Verdict | Issue |
| Button (x3 impls) | src/... | atom | consolidate | 3 duplicate implementations |
| UserProfile | src/... | ??? | split | fetches + validates + renders (412 lines) |
| Card | src/... | organism | keep | — |
## Refactors applied
1. [name] — what changed, files touched, why (one line each)
## Refactors recommended (not applied)
1. [name] — payoff, estimated blast radius
## Conventions going forward
- Directory structure: [atoms/molecules/organisms or project's own scheme]
- Prop rules adopted: [union variants, no conflicting booleans, ...]
- When to extract: [the 2–3 rule as applied to this codebase]
Quality bar (check before delivering)
Hard don'ts: don't rename the user's public component APIs without flagging it as breaking; don't introduce a new state-management or styling library as a side effect; don't atomize prematurely — a 40-line coherent component doesn't need splitting.
Integration
skills/frontend-design/design-foundation → feeds this skill the token vocabulary components should consume (spacing/color/type variables).
skills/frontend-design/interaction-physics ← consumes your component states (hover/active/loading) and animates them.
skills/frontend-design/loading-states and skills/frontend-design/error-handling-recovery ← consume your component inventory to add loading/error variants systematically.
skills/frontend-design/accessibility-excellence ← audits the components you produce; build with semantic elements so it has less to fix.
References
references/patterns.md — full code examples per atomic level, single-responsibility before/after, controlled/uncontrolled implementations, the component documentation template, and size conventions. Read it when actually writing the refactored code or docs.
1---2name: component-architecture3description: Audit and refactor a frontend codebase's component structure, or design a component library from scratch, using atomic design, composition, and disciplined prop interfaces. Use when the user says 'my components are a mess', 'this component is 800 lines', 'refactor my components', 'build a component library', 'how should I structure my components', 'too much prop drilling', 'we keep rebuilding the same button', or asks where a new component should live — even if they never say 'atomic design'. Produces a component inventory audit, refactored component code (extracted atoms/molecules, typed prop interfaces, variant systems), and per-component documentation.4---5
6# Component Architecture
7
8Turn a tangle of one-off components into a composable system: audit what exists, classify it into atomic levels, then refactor the worst offenders into small, typed, documented pieces. **The prime directive: a component earns its existence by having one responsibility and a prop interface that makes invalid states unrepresentable.** Deliver working refactored code plus an audit the user can act on — never just advice.
9
10## When to use / when not to
11
12Use for: component decomposition, prop interface design, variant systems, extracting a shared library, deciding controlled vs uncontrolled, component documentation.
13
14Hand off instead when the real need is:
15- Visual tokens (spacing, color, type scales) → `skills/frontend-design/design-foundation`
16- Animation/feedback inside components → `skills/frontend-design/interaction-physics`
17- Keyboard/ARIA behavior of components → `skills/frontend-design/accessibility-excellence`
18- Render performance (memoization, re-renders) → `skills/frontend-design/performance-optimization`
19- Unsure where to start across the whole frontend → `skills/frontend-design/frontend-orchestrator`
20
21## Step 0 — Inspect the codebase, then ask only what's left
22
23Before proposing anything, build a component inventory from the actual code:
24
251. Locate component directories (`components/`, `ui/`, `src/app/**`, `lib/`). Note the framework and styling approach (Tailwind, CSS Modules, CSS-in-JS, vanilla) — match it; never introduce a new styling system uninvited.
262. Count components and flag: files > ~200 lines, components that both fetch data and render detailed markup, duplicated UI (multiple button/input/card implementations), inline styles repeating the same values, class-based inheritance.
273. Check for an existing design system or UI kit (shadcn/ui, MUI, Chakra, internal package). If one exists, extend its conventions — don't build a parallel system.
28
29Ask the user (one batch, only what the code didn't answer): **scope** (whole app, one feature, or one painful component?) and **whether a shared library/package is the goal or just cleaner local structure**. If the request already implies scope ("refactor this file"), don't ask — state assumptions and proceed.
30
31## Workflow
32
33### 1. Classify the inventory into atomic levels
34
35- **Atoms** — indivisible, no component dependencies: Button, Input, Label, Icon, Badge, Spinner.
36- **Molecules** — small compositions of atoms with one purpose: FormInput (Label+Input+Error), SearchBar.
37- **Organisms** — sections with business purpose and often state: NavBar, Card, Modal, Form.
38- **Templates** — page layouts arranging organisms; not reusable across page types.
39- **Pages** — templates with real data; use them to find edge cases.
40
41Decision rule: if you can't classify a component, it's doing too much — that's a refactor candidate, not a taxonomy problem.
42
43### 2. Prioritize refactors by leverage
44
45Order: (1) duplicated atoms (consolidate first — everything else builds on them), (2) god components violating single responsibility, (3) prop interfaces that allow invalid states, (4) missing variants forcing copy-paste. Propose the top 3–5 refactors with a one-line payoff each; have the user confirm scope before rewriting broadly. For a single-component request, skip the vote and refactor it.
46
47### 3. Refactor with these decision rules
48
49- **Split rule:** a component that fetches data, manages form state, AND renders detailed markup becomes an orchestrator plus focused children. Split by responsibility, not by line count.
50- **Composition over inheritance, always.** Variants are props (`variant`, `size`), presets are thin wrappers — never subclasses.
51- **Controlled vs uncontrolled:** if any other UI must react to the value while editing (live validation, dependent fields, character counts) → controlled. Fire-and-forget input read once on submit → uncontrolled is fine. Never mix modes in one component.
52- **Prop interface rules:** union types instead of booleans that can conflict (`variant: 'primary' | 'danger'`, not `isPrimary` + `isDanger`); constrain to valid options; pass through `className` and ARIA attributes; callbacks named `on<Event>`. If two boolean props can combine into an invalid state, redesign the interface.
53- **Extraction threshold:** extract a shared component at the 2nd–3rd duplication *if* the copies are genuinely the same concept. Two things that look alike but change for different reasons stay separate — wrong abstractions cost more than duplication.
54
55Canonical shape for an atom (full gallery in `references/patterns.md`):
56
57```typescript
58interface ButtonProps {
59 variant?: 'primary' | 'secondary' | 'ghost' | 'danger';
60 size?: 'sm' | 'md' | 'lg';
61 disabled?: boolean;
62 loading?: boolean;
63 onClick?: () => void;
64 children: React.ReactNode;
65}
66
67export const Button = ({ variant = 'primary', size = 'md', disabled, loading, ...rest }: ButtonProps) => (
68 <button
69 className={`button button--${variant} button--${size}`}
70 disabled={disabled || loading}
71 {...rest}
72 />
73);
74```
75
76### 4. Document what you build
77
78Every extracted/refactored shared component gets docs: purpose, props table, variants with when-to-use, states, accessibility notes, edge cases. Use the template in `references/patterns.md`. Put docs where the team will see them (Storybook stories if Storybook exists, otherwise a colocated `README.md` or JSDoc).
79
80## Required output format
81
82Deliver both artifacts:
83
84**1. The code** — refactored/created component files, edited in place, following the project's existing styling and naming conventions. All call sites updated; the app must still compile.
85
86**2. Component Architecture Audit** (markdown):
87
88```
89## Component Inventory
90| Component | File | Level | Verdict | Issue |
91| Button (x3 impls) | src/... | atom | consolidate | 3 duplicate implementations |
92| UserProfile | src/... | ??? | split | fetches + validates + renders (412 lines) |
93| Card | src/... | organism | keep | — |
94
95## Refactors applied
961. [name] — what changed, files touched, why (one line each)
97
98## Refactors recommended (not applied)
991. [name] — payoff, estimated blast radius
100
101## Conventions going forward
102- Directory structure: [atoms/molecules/organisms or project's own scheme]
103- Prop rules adopted: [union variants, no conflicting booleans, ...]
104- When to extract: [the 2–3 rule as applied to this codebase]
105```
106
107## Quality bar (check before delivering)
108
109- [ ] Every refactored component has exactly one responsibility you can state in one sentence
110- [ ] No prop interface permits an invalid state (no conflicting booleans, no unconstrained strings for variants)
111- [ ] No inheritance for variants anywhere in delivered code
112- [ ] Each shared component is explicitly controlled or uncontrolled, never both
113- [ ] Interactive components keep keyboard operability and visible focus (don't strip what existed)
114- [ ] All call sites updated; imports resolve; existing styling system respected
115- [ ] Every new shared component has docs (purpose, props, variants, states)
116- [ ] Audit table covers the inspected scope, not just the files you touched
117
118Hard don'ts: don't rename the user's public component APIs without flagging it as breaking; don't introduce a new state-management or styling library as a side effect; don't atomize prematurely — a 40-line coherent component doesn't need splitting.
119
120## Integration
121
122- `skills/frontend-design/design-foundation` → feeds this skill the token vocabulary components should consume (spacing/color/type variables).
123- `skills/frontend-design/interaction-physics` ← consumes your component states (hover/active/loading) and animates them.
124- `skills/frontend-design/loading-states` and `skills/frontend-design/error-handling-recovery` ← consume your component inventory to add loading/error variants systematically.
125- `skills/frontend-design/accessibility-excellence` ← audits the components you produce; build with semantic elements so it has less to fix.
126
127## References
128
129- `references/patterns.md` — full code examples per atomic level, single-responsibility before/after, controlled/uncontrolled implementations, the component documentation template, and size conventions. Read it when actually writing the refactored code or docs.