Utility-First CSS
.card, .card__header) and defining its styles in a separate stylesheet, you compose the look of an element directly in markup from many small, single-purpose utility classes — each one doing exactly one thing, like setting display, spacing, or a color.What it looks like
<div class="flex items-center gap-4 rounded-lg border border-gray-200 p-4 shadow-sm">
<img class="h-12 w-12 rounded-full" src="avatar.jpg" alt="" />
<div class="flex flex-col">
<span class="text-sm font-semibold text-gray-900">Jane Doe</span>
<span class="text-xs text-gray-500">Product Designer</span>
</div>
</div>No custom class was written and no separate stylesheet was touched — every visual decision is legible directly from the class list on the element itself.
Tailwind CSS: the dominant implementation
The debate
In favor | Against |
|---|---|
No context-switching — styling happens right where the markup is, no jumping to a separate CSS file | Markup gets verbose and visually noisy, especially for complex components |
Consistent, constrained design tokens — you can't invent a slightly-off spacing or color value | Some argue it violates separation of concerns by mixing presentation into markup |
No dead CSS accumulating over time — you only ever compose classes that already exist | Repetition across markup unless you extract components — the 'utility soup' complaint |
Refactoring a component visually rarely requires touching a stylesheet at all | A steeper initial learning curve — memorizing a large utility vocabulary |
Extracting repetition
In practice, teams rarely repeat long utility strings by hand — they extract a component (a React/Vue component, a framework partial, or a class composition helper) once and reuse the component, not the raw class string:
function Avatar({ name, title, src }) {
return (
<div className="flex items-center gap-4 rounded-lg border border-gray-200 p-4 shadow-sm">
<img className="h-12 w-12 rounded-full" src={src} alt="" />
<div className="flex flex-col">
<span className="text-sm font-semibold text-gray-900">{name}</span>
<span className="text-xs text-gray-500">{title}</span>
</div>
</div>
)
}