Components First, Then Pages
Without unified components, the page will always look stitched together.
Lock down the dozen or so most common components first, then build pages out of them. Do it the other way around and every page grows its own style.
What you'll run into:
- The same button has different radius, type size, and padding on different pages
- Changing one style means editing seven or eight files—and you still miss two
- You ask the AI for a new page and it invents yet another card style
This problem is especially sharp in vibecoding. The AI only ever sees the current page—it has no global view—so every page means it reinvents the button. Without a ready-made component set, it will absolutely make its own.
Components-first has a side benefit: it turns a design decision from "every time" into "once." Once the button's corner radius is set, the next few dozen pages never have to think about it again. That's the core value of a design system: fixing repeated visual decisions into reusable assets instead of redoing them per page. design-systems-101
On a more practical level, components-first is also a safety net for AI coding. When the AI generates a page, its default is to improvise based on the current page's context—if you don't define components, you're effectively allowing it to improvise every time. The debt from these scattered decisions compounds and erupts after the fifth page, when unifying retroactively costs several times as much.
Which dozen to lock first
| Component | What to define |
|---|---|
| Button | Primary / secondary / danger, each with default, hover, pressed, disabled, loading states |
| Input | Default, focus, error, disabled, read-only, plus label and helper-text placement |
| Card | Padding, radius, border or shadow—pick one, not both |
| List item | Row height, divider, hover state, selected state |
| Tag | One set of status colors, one or two sizes |
| Modal / drawer | Fixed structure: width, header area, content area, button area |
| Empty / loading / error | Three shared components reused across the site (see four states) |
| Toast | Success, warning, error, with unified placement and dismiss timing |
These eight cover most interfaces. Once they're defined, new pages are basically assembly work with no style decisions left. At the start, you can get away with just the trio—button, input, card—then add the rest after the first page works. Don't stop for three months to design a "complete" system.
When you define them, write the exact values—not "slightly smaller radius." Values should come from the spacing and type scale variables, not invented per component. Even better, reference the variable names: writing radius-1 beats writing "8px radius"—the former doesn't require touching dozens of places when the theme changes.
Note for the AI
CLAUDE.md · Component rules
## Components
Existing components live in src/components/ui/.
Before building any page, read through this directory first.
Hard requirements:
- When you need a button, input, card, list item, tag, modal,
empty state, loading state, or error state, always use the
existing components. No inline styles in pages, and no
creating new components of the same kind.
- If an existing component doesn't fit, tell me what's missing
and how you'd extend it (a new variant or a new prop), then
wait for my confirmation. Don't work around it by writing
your own.
- New components must reference design variables for
color / spacing / type / radius. No hardcoded values.
- Every component implements its full set of states:
five states for buttons, five for inputs.
After finishing a page, list every component you used,
and whether you created or modified any component.
That last line is a lightweight audit. It lets you catch the AI quietly inventing a new component, instead of discovering on page five that the style has drifted.
How to verify. On a new page, deliberately skip the component directory and let the AI improvise, then count how many components it "invented" against the list. Zero means the rules are working. Two or three or more means the library has coverage gaps—add the missing components to the library first, then keep building pages. Don't let one-off styles land in the codebase.
