Tailwind CSS Introduction
Tailwind is a utility-first CSS framework: instead of writing a custom class per component (.card, .card-title) and defining its properties in a stylesheet, you compose small, single-purpose utility classes directly in markup (flex, p-4, text-lg). Every utility maps to a small, fixed set of CSS declarations, so the framework is really a very large, consistent vocabulary layered on top of ordinary CSS you already know.
Utility-first philosophy
The pitch is that naming things is hard and stylesheets rot — a .card class quietly grows overrides over years until nobody trusts changing it. Utility classes sidestep both problems: there is nothing to name, and a class like p-4 means exactly one thing everywhere in the codebase, forever.
<!-- Traditional CSS --> <div class="card"> <h2 class="card-title">Plan: Pro</h2> <p class="card-price">$19/mo</p> </div> <!-- Tailwind utility-first --> <div class="rounded-lg border border-slate-200 p-6 shadow-sm"> <h2 class="text-xl font-semibold">Plan: Pro</h2> <p class="mt-2 text-2xl font-bold text-blue-600">$19/mo</p> </div>
Setup with Vite or Next.js
npm install tailwindcss @tailwindcss/vite # Vite (Tailwind v4) # or, for Next.js: npm install tailwindcss @tailwindcss/postcss postcss
/* globals.css — Tailwind v4: one import, no config file required to start */ @import "tailwindcss";
tailwind.config.js + content glob setup in favor of automatic content detection and CSS-native configuration — see the CSS-first config section below.Core utilities mapped to CSS you already know
Utility | Equivalent CSS |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
| A predefined small |
|
|
Numeric scale utilities (p-4, gap-6, w-64) map onto a consistent spacing scale rather than arbitrary pixel values — this is the same idea as the design-token spacing scales built by hand with Sass maps (see Sass Control Directives), just pre-built and shipped as classes.
Responsive prefixes
Breakpoint prefixes turn any utility into a media-query-scoped one — mobile-first, applying at that breakpoint and above.
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4"> <!-- 1 column on mobile, 2 from the sm breakpoint up, 4 from lg up --> </div>
Prefix | Min-width (default scale) |
|---|---|
| 40rem (640px) |
| 48rem (768px) |
| 64rem (1024px) |
| 80rem (1280px) |
| 96rem (1536px) |
State variants
<button class="bg-blue-600 hover:bg-blue-700 focus-visible:ring-2 disabled:opacity-50"> Save </button>
hover:, focus:, focus-visible:, disabled:, dark:, and dozens more variant prefixes compose with any utility — hover:bg-blue-700 compiles to a :hover rule, dark:text-white to a rule scoped under a dark-mode selector or media query.
@apply and when not to reach for it
@apply lets you fold a group of utilities back into a single custom class, for the cases where a component is reused often enough that repeating the same utility string everywhere becomes noise.
.btn-primary {
@apply rounded-lg bg-blue-600 px-4 py-2 font-semibold text-white hover:bg-blue-700;
}@apply sparingly. Used heavily, it just recreates the "one class with many properties, hard to trace" model Tailwind exists to avoid — a JS/JSX component wrapping the raw utility classes is usually the better way to deduplicate repeated markup in component-based frameworks like React.Config and theme tokens
Tailwind v4 moved configuration into CSS itself via the @theme directive, replacing the old JavaScript tailwind.config.js for most projects.
/* globals.css */
@import "tailwindcss";
@theme {
--color-brand: oklch(0.6 0.2 260);
--spacing-18: 4.5rem;
--font-display: "Cal Sans", sans-serif;
}Every custom property defined inside @theme automatically becomes both a CSS variable (usable anywhere as var(--color-brand)) and a new utility (bg-brand, p-18, font-display) — one declaration, two ways to use it.
Honest pros and cons
Pros | Cons |
|---|---|
No naming fatigue — nothing new to invent per component | Markup gets visually noisy, especially for complex responsive/state combinations |
Styles are colocated with markup — easy to see exactly what a specific element looks like | Learning the utility vocabulary and scale is its own upfront cost |
A constrained design-token scale discourages one-off magic numbers | Genuinely custom, one-off visual designs can still require dropping to plain CSS anyway |
Small final CSS bundle — only used utility combinations are generated | Diffs in code review show utility soup rather than a semantic class name, which some teams find harder to review |
@apply or plain CSS only where it earns its keep.Related pages: Tailwind Configuration & Theming, Utility-First CSS, CSS Custom Properties, and PostCSS.