</> ConvertAtlas Developer Tools
Level 3 · Advanced — Modern CSS Lesson 34 Advanced 13 min

Component-Based Styling

Think in reusable components with encapsulated, composable styles, variants and states.

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.

HTML
<button class="btn">Default</button>
<button class="btn btn--primary">Primary</button>
<button class="btn btn--ghost">Ghost</button>
CSS
.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}
Result
One base .btn, layered variants with modifiers.

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.

HTML
<button class="btn btn--primary">Normal</button>
<button class="btn btn--primary is-active">Active</button>
<button class="btn btn--primary" disabled>Disabled</button>
CSS
.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}
Result
Variants and states, all on the component.

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.

Common mistake
Don't
.card { margin-bottom: 24px; }
Do
.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.

Best practice

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.

Try it yourself

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.

Quick quiz

1. What holds the shared styles of a component?

2. Where should spacing between components live?

3. Why keep components self-contained?

Key takeaways
  • 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.