Why Tailwind?
The utility-first philosophy. Tailwind v4 in 2026.
Tailwind CSS is the most divisive frontend tool of the last decade. Half the internet swears by it; the other half writes long blog posts about why it ruined CSS. Both camps are missing the point. Tailwind isn't about classes vs CSS files. It's about a workflow: you build components by composing tiny utilities, never leaving your markup, never naming a class. Whether that's right for you depends on what kind of team you're on.
The utility-first philosophy
Traditional CSS thinks in components: write a .card class, define what a card looks like, reuse it. Tailwind thinks in utilities: ship a giant alphabet of single-purpose classes (p-4 = padding 1rem, text-lg = larger text, bg-blue-500 = a specific blue) and let you compose them inline.
<!-- Traditional CSS -->
<div class="card">
<h3 class="card-title">Hello</h3>
</div>
<style>
.card { padding: 16px; background: white; border-radius: 8px; }
.card-title { font-size: 18px; font-weight: 600; }
</style>
<!-- Tailwind -->
<div class="p-4 bg-white rounded-lg">
<h3 class="text-lg font-semibold">Hello</h3>
</div>Same output. The Tailwind version skips the class naming and the stylesheet entirely. Every utility is a known quantity from a designed system.
Why it scales for teams
The traditional approach breaks down at scale for one boring reason: naming things is hard. Five developers come up with five different names for a card. You end up with .card, .product-card, .card-v2, .shadow-card, and a graveyard of dead styles. CSS bundles grow forever because nothing is safe to delete.
- No naming.You don't invent class names. You compose from a fixed vocabulary.
- No dead styles. Tailwind only ships classes you actually use. Removing a component automatically removes its styles.
- Consistent design system.Spacing, colors, and type scales come from one config. Developers can't just write
padding: 17pxbecause they feel like it. - Locality.Markup and styles live next to each other. No more "what file is this class defined in?"
p-4 flex items-center gap-2as fluently as English. The class names are dense, but they're also extremely consistent, which is the opposite of custom CSS.The Tailwind v4 mental model
Tailwind v4 (released 2024) changed how you configure the framework. The old tailwind.config.js still works, but the new idiomatic approach is to configure everything in CSS itself using @theme.
@import "tailwindcss";
@theme {
/* Add or override design tokens */
--color-brand: oklch(0.6 0.18 270);
--color-brand-light: oklch(0.8 0.1 270);
--font-display: "Inter Tight", sans-serif;
--spacing: 0.25rem; /* the base scale unit */
--radius-lg: 0.75rem;
}Now bg-brandjust works in your HTML, with no config file. The tokens you declare become Tailwind utilities automatically. It's closer to plain CSS than v3 ever was.
Dark mode in two lines
Tailwind ships dark mode as a prefix: dark:bg-zinc-900 applies bg-zinc-900only when dark mode is active. The default strategy is "follow the OS," controlled by the prefers-color-scheme media query.
<body class="bg-white text-zinc-900 dark:bg-zinc-900 dark:text-zinc-100">
<h1 class="text-3xl font-bold">Hello, themes</h1>
</body>For a class-based toggle (where you put a .dark class on the html element via JS), tell Tailwind to look for it:
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));Now flipping document.documentElement.classList.toggle('dark') in JS switches the whole theme.
The trade-off vs CSS Modules and others
Tailwind isn't the only modern option. CSS Modules, vanilla extract, and styled-components all solve the same scaling problems differently. Roughly:
- CSS Modules:write normal CSS, scoped by file. Familiar, but you're still naming things and the bundle still grows. Good middle ground for teams that want CSS.
- Styled-components / Emotion: styles in JS, template-literal CSS. Great DX, but you ship a runtime to every user. Mostly out of favor in 2026.
- Tailwind: utilities only, no naming, smallest shipping CSS for the surface area covered. Best for product teams that move fast and share a design language.
- Plain CSS: still works! For a small site, a single
style.cssis fine. Don't over-engineer.
class="..." attributes get long, especially with responsive prefixes. Markup becomes harder to read at a glance. The class vocabulary is opinionated, and learning it has a real cost. If your team writes deeply expressive CSS (animations, complex transforms), you'll still drop into custom CSS for parts.The compromise: extract components when they repeat
The classic anti-Tailwind argument is "but you're repeating the same classes over and over." The answer is: you extract a component in your view layer (React, Vue, Astro, anything), not a CSS class. The classes live in one place, the call site is clean:
function Button({ children }) {
return (
<button className="px-4 py-2 rounded-md bg-indigo-600 text-white font-medium hover:bg-indigo-700">
{children}
</button>
);
}
// Call sites: just <Button>Save</Button>That's the "Tailwind way." Reuse via components, not classes.
When to use Tailwind, and when not
Reach for Tailwind when:
- You're on a team where CSS file growth is a problem.
- You're building a product UI with hundreds of components.
- You want strong design system enforcement (designers and devs share one spacing scale).
- You're using a component framework (React, Vue, etc.).
Skip Tailwind when:
- The project is one or two HTML files.
- You're doing heavy art-directed design where every page is unique (use plain CSS).
- The team really cannot tolerate utility soup in markup (rare but real).
Quiz
What's the central idea behind 'utility-first CSS'?
Recap
- Tailwind is utility-first: small composable classes instead of named component classes.
- v4 configures via
@themein CSS, not a JS config file (though that still works). - Dark mode: prefix utilities with
dark:; choose media query or class-based strategy. - Reuse looks via component extraction (one React component), not shared CSS classes.
- Trade-off: less naming, smaller CSS, more verbose markup. Best for product teams with component frameworks.