Episode 1 — Fundamentals / 1.10 — CSS Architecture and Project Structure
1.10.c — Utility vs Component Classes
In one sentence: Utility classes apply one declaration each and are composed in HTML; component classes bundle many declarations behind a semantic name — and the industry keeps swinging between the two.
Navigation: ← 1.10.b — Component-Based CSS · 1.10.d — Real-World Folder Structure →
1. Two philosophies at a glance
Component class Utility classes
───────────────────────────── ─────────────────────────────────
<button class="btn btn--primary"> <button class="bg-blue-600
Submit text-white font-bold py-2 px-4
</button> rounded hover:bg-blue-700">
Submit
.btn { … 12 declarations … } </button>
.btn--primary { … 4 declarations … }
Each class = 1 declaration (in CSS)
Neither is universally "right." Both solve real problems — understanding when each shines is the skill.
2. What utility classes are
A utility class maps to a single CSS declaration (sometimes two closely related ones):
| Class | What it does |
|---|---|
.text-center | text-align: center |
.mt-4 | margin-top: 1rem |
.flex | display: flex |
.rounded-lg | border-radius: 0.5rem |
.sr-only | Visually hidden, accessible to screen readers |
Utility libraries ship hundreds of these — Tailwind CSS is the most popular.
3. What component classes are
A component class bundles all visual rules behind one meaningful name:
.btn {
display: inline-flex;
align-items: center;
padding: 0.5rem 1rem;
font-weight: 600;
border-radius: 0.375rem;
cursor: pointer;
transition: background-color 150ms;
}
Component frameworks like Bootstrap live here: you apply .btn .btn-primary and the CSS handles everything.
4. Pros and cons
| Criterion | Utility-first | Component-class |
|---|---|---|
| Speed of prototyping | Very fast — style without leaving HTML | Moderate — write CSS, pick class names |
| Consistency | Enforced by design tokens (spacing-4 = always 1rem) | Depends on discipline |
| Readability of HTML | Noisy class lists | Clean, semantic class names |
| Readability of CSS | Minimal custom CSS to read | Large stylesheets to navigate |
| File size | Small (purge unused) | Can grow with dead selectors |
| Refactoring | Change HTML, not CSS | Change CSS, not HTML |
| Reusability | Extract with @apply or framework components | Inherit / extend in CSS |
| Learning curve | Memorise class vocabulary | Learn naming conventions |
| Specificity issues | Rare (single class, same weight) | Possible if conventions break down |
5. The "it's just inline styles" argument
Critics say utility classes are inline styles with extra steps. Here's why that comparison breaks down:
| Inline styles | Utility classes |
|---|---|
| No media queries | Responsive variants: md:flex, lg:grid-cols-3 |
| No pseudo-classes | State variants: hover:bg-blue-700, focus:ring-2 |
| No design constraints | Constrained scale: you can only use mt-2, mt-4, not mt-37px |
| Style attribute specificity (high) | Class specificity (low, composable) |
| No reuse across elements | Same class reused everywhere |
| Hard to search/audit | grep "bg-blue" finds every use |
Utility classes are a design-token system delivered through class names, not random inline declarations.
6. The hybrid approach
Most real projects mix both:
<!-- Component class for the card structure -->
<div class="card">
<h2 class="card__title">Dashboard</h2>
<!-- Utility classes for one-off spacing / alignment -->
<p class="card__text mt-2 text-gray-600">Overview of your metrics.</p>
</div>
Rules of thumb for hybrids:
- Repeated patterns → extract a component class.
- One-off tweaks (spacing, alignment, colour overrides) → utility class.
- Complex interactive states → component class with modifiers.
- Layout primitives (flex, grid, gap) → utilities often win.
7. When utilities win vs when components win
| Scenario | Better approach |
|---|---|
| Rapid prototyping or MVPs | Utilities |
| Design-system components used across many projects | Component classes |
| Highly custom, non-repeating layouts | Utilities |
| Email templates (inline style fallback needed) | Component classes |
| Large team with strict design tokens | Utilities (enforced constraints) |
| Open-source library consumed by others | Component classes (cleaner API) |
8. Framework comparison
| Framework | Philosophy | Class example |
|---|---|---|
| Tailwind CSS | Utility-first; extract components via @apply or framework templates | class="flex items-center gap-4 p-4 rounded-lg shadow" |
| Bootstrap | Component-first; utilities added later (v5+) | class="btn btn-primary btn-lg" |
| Bulma | Component-first, no JS | class="button is-primary is-large" |
| Tachyons | Pure utility (predecessor to Tailwind's ideas) | class="flex items-center pa3 br3" |
9. Key takeaways
- Utility classes = one class, one job; composed in HTML. Fast, constrained, auditable.
- Component classes = semantic names; hide implementation in CSS. Clean HTML, reusable API.
- Utilities are not inline styles — they support responsive, pseudo-class, and design-token constraints.
- Most production codebases use a hybrid — components for structure, utilities for fine-tuning.
- The choice is not religious; match the tool to the project size, team, and reuse requirements.
Explain-It Challenge
Explain without notes:
- Give three concrete differences between utility classes and inline
styleattributes. - A teammate says: "We should use only utility classes and never write component CSS." Argue for and against.
- When would you extract a set of utility classes into a named component class?
Navigation: ← 1.10.b — Component-Based CSS · 1.10.d — Real-World Folder Structure →