Modern interfaces are built from components — a button, a card, a badge — used over and over. Styling them as self-contained, composable units (rather than one-off page styles) is the mindset behind every design system and framework.
A base class plus modifiers
A component has a base class that holds everything shared, then modifier classes for variants. The base never changes; modifiers layer on differences. This avoids duplicating the shared styles for every variant.
<button class="btn">Default</button>
<button class="btn btn--primary">Primary</button>
<button class="btn btn--ghost">Ghost</button>.btn{font:inherit;padding:9px 16px;border-radius:9px;border:1px solid #cbd5e1;background:#fff;cursor:pointer}
.btn--primary{background:#2563eb;color:#fff;border-color:#2563eb}
.btn--ghost{background:transparent;border-color:#2563eb;color:#2563eb}States as modifiers too
States (active, disabled, loading) follow the same pattern — either pseudo-classes (<code>:disabled</code>) or state classes (<code>.is-active</code>). Keeping them on the component keeps everything about a button in one place.
<button class="btn btn--primary">Normal</button>
<button class="btn btn--primary is-active">Active</button>
<button class="btn btn--primary" disabled>Disabled</button>.btn{font:inherit;padding:9px 16px;border-radius:9px;border:0;background:#2563eb;color:#fff;cursor:pointer}
.btn.is-active{background:#1e3a8a}
.btn:disabled{opacity:.5;cursor:not-allowed}Composition over duplication
Build complex UI by composing small components rather than writing bespoke CSS for each page. A card contains buttons and badges; a page contains cards. Each piece is reusable and tested once.
Self-contained components
A good component does not depend on where it sits — no fixed margins that assume a neighbour, no styles leaking out. Spacing between components belongs to the layout, not the component. This makes components portable, exactly what container queries reinforce.
.card { margin-bottom: 24px; }.grid { gap: 24px; } /* layout owns spacing */Baking outer margins into a component, so it breaks when reused elsewhere. Let the layout own spacing between components.
Give each component a base class plus modifiers for variants and states, keep it self-contained (no outer margins), and compose pages from components. This is the bridge to building a design system.
Build a .badge component with a base class and three modifiers (--success, --warning, --danger). Keep all spacing internal and verify it looks right placed anywhere.
1. What holds the shared styles of a component?
2. Where should spacing between components live?
3. Why keep components self-contained?
- Components have a base class plus modifiers for variants and states.
- Compose pages from small, reusable components.
- Keep components self-contained — no outer margins.
- Layout owns the spacing between components.