Web Component Development
Workflow
Phase 1: Design Extraction
Step 1: Overview (you do this yourself)
You MUST personally inspect the design before delegating anything:
- Fetch Figma node via MCP (, ).
- Take a screenshot — study the overall visual: layout structure, hierarchy, proportions, and color balance.
- Understand the design intent, component relationships, and visual rhythm.
- Identify distinct components or layers that need detailed extraction (e.g. header, card, button, icon group).
Do NOT skip this step or delegate it. You need the high-level context to coordinate subagents effectively.
Step 2: Parallel deep-dive (MUST delegate to subagents)
You MUST spawn subagents in parallel to extract detailed specs for each identified component/layer. Do NOT attempt to extract fine-grained details yourself — subagents have dedicated context for exhaustive spec extraction.
Each subagent extracts:
- Font: family, weight, size, line-height, letter-spacing, text-align, text-transform, text-decoration.
- Color: foreground, background (solid/gradient), border, opacity (exact values including alpha).
- Spacing: padding, margin, gap (every direction).
- Dimensions: width, height, min/max constraints.
- Effects: border-radius (per corner), border-width, box-shadow (offset, blur, spread, color), opacity, overflow.
- Icons: sizing, stroke width, color.
- States: hover, active, focus, disabled variations if present.
Each subagent should:
- Fetch the specific node's and .
- Record ALL specs exhaustively — leave nothing unspecified.
- Map Figma tokens to project design system tokens where they exist; use raw values only when no token matches.
- Return a structured spec object for the component.
Step 3: Synthesis
Collect and merge all subagent results into a unified design spec before proceeding to implementation.
Phase 2: Implementation
Start small. Start simple.
Build the smallest possible working version first with an elegant, minimal API.
- Do NOT add anything beyond what the design shows — no bonus features, no "improvements", no embellishments.
- Do NOT write hacky code — if the approach feels wrong, step back and redesign.
- Do NOT over-engineer for hypothetical future requirements.
Once verified correct, we incrementally add functionality.
Write the component following these principles:
Design fidelity — Faithfully convey the design's
intent, not pixel-for-pixel reproduction of static values. Round obviously unreasonable fractional values that are Figma artifacts (e.g.
→
). Adapt static layouts to responsive/interactive reality. The design is a communication, not a specification.
Shallow DOM — Use modern CSS layout (
,
) directly. Avoid wrapper divs that exist only for styling. Every DOM node should carry semantic or layout purpose.
Border & stroke strategy — Choose deliberately:
| Technique | Layout impact | When to use |
|---|
| Yes (shrinks content) | When border is part of the sizing model |
| + negative | No | Non-layout-affecting focus rings, selection |
| (inset or outset) | No | Decorative strokes, glow, elevation |
| Absolute overlay with | No | Complex multi-layer strokes on rounded corners |
Maintain border-radius concentricity:
inner-radius = outer-radius − border-width
.
Typography — Set every parameter explicitly:
,
,
,
,
,
. Do not rely on inherited or default values for components.
Color — Use exact values from Figma including alpha. Prefer
or Tailwind opacity modifiers (
) over approximation. Add
variants for colors that lose contrast on dark backgrounds.
Touch targets — For buttons and clickable elements with small visual footprints, use an absolutely positioned
pseudo-element (or a child div) with negative inset to expand the interactive area to at least 44×44px without affecting layout.
Animations — Use Motion (previously Framer Motion). Always call
and skip or simplify animation when true. This also ensures deterministic screenshot testing.
Phase 3: Stories
Write Storybook stories covering every meaningful variant before visual verification.
- One story per variant/state.
- A single composite story that elegantly lays out all variants — just the components themselves, no extra labels or decorations.
- Use seeded/deterministic data — no or in stories. Use hardcoded values or a seeded PRNG.
Layout mode — Ask: "Am I showing a specimen, or simulating a host?"
| Mode | When | Example |
|---|
| Displaying a self-contained component whose size is determined by its content | Button, Badge, Input, Card |
| Simulating a real page host where the component fills or arranges within space | Dashboard, list page, split-pane, sidebar |
Container width — When a component's width semantics depend on "how wide is my host" (Card, Dialog, Form), use a decorator to provide an explicit width container:
tsx
export const Default: Story = {
decorators: [
(Story) => (
<div className="w-[360px] max-w-full">
<Story />
</div>
),
],
};
Do NOT hard-code a width when the component is meant to participate in page-level layout (
,
,
). Instead, provide a layout container that defines the spatial context (fullscreen + padding wrapper,
content area, explicit grid/flex parent).
Rule of thumb:
unit component story → + explicit wrapper width; page/region component story → + layout container.
Phase 4: Browser Verification
Always verify every component in the browser before considering it done.
- Open the story's iframe URL directly (e.g.
http://localhost:6006/iframe.html?id=components-button--default
) to get the isolated component without Storybook chrome.
- Inspect the rendered DOM — confirm every CSS property matches the Figma spec:
- Font: family, weight, size, line-height, letter-spacing.
- Color: foreground, background, border, opacity.
- Spacing: padding, margin, gap — verify computed values, not just class names.
- Dimensions: width, height, border-radius.
- Take a screenshot for visual comparison against the Figma screenshot.
- If anything is off, fix it and re-verify. Do not proceed until the component matches.
Phase 5: Testing
Only after browser verification confirms the component is correct:
- Write unit tests (React Testing Library) covering rendering, props, accessibility, visual styles.
- Update snapshots ( flag).
- Add visual regression (screenshot) tests if the project uses them.
- Run tests and confirm all pass.
Phase 6: Commit
Only after all tests pass and browser verification is complete:
- Run .
- Commit with conventional commit message.
Decomposition
Always build bottom-up: atomic components first, then compose.
- Identify the smallest, most reusable pieces (buttons, icons, badges, text styles).
- Build each atomic component through the full cycle (implementation → stories → browser verification → tests) independently.
- Only after each atomic component is verified and stable, compose them into molecules (card, list item, form field).
- Continue composing upward into organisms and full layouts.
Do NOT build top-down by creating a large component and extracting pieces later — this leads to tightly coupled, hard-to-test code.
Separation of Concerns
For any component with non-trivial logic, split presentation from logic:
| Layer | Responsibility | Tests |
|---|
| Presentation | Visual rendering, styling, layout. Props are primitives and ReactNode. No data fetching, no side effects. | Storybook stories, snapshot tests, screenshot tests |
| Container | Data fetching, state management, event handling. Composes presentation components. | Unit tests for logic, integration tests for data flow |
Presentation components must render identically given the same props — no internal randomness, no time-dependent rendering.
This separation is NOT optional for complex components. It enables:
- Independent visual iteration in Storybook without mocking data layers.
- Logic testing without rendering overhead.
- Reuse of presentation across different data sources.
Anti-Patterns
- Do not commit snapshots/screenshots before browser verification — they lock in wrong output.
- Do not guess font or color values — always extract from Figma or inspect in browser.
- Do not add animation without guard — breaks screenshot tests and a11y.
- Do not use non-deterministic random data in stories — breaks visual regression.
- Do not add empty wrapper divs — if a div has only one class for one child, the class belongs on the child.
- Do not use when you need zero layout impact — use , , or an overlay instead.