TL;DR
- Tailwind v4: Ground-up rewrite. CSS-first config (no
tailwind.config.js). 5x faster builds. - New setup:
@import "tailwindcss"+@theme {}block in CSS. Zero config to start. - Key changes: Container queries built-in, 3D transforms,
@starting-styletransitions, P3 colors. - Oxide engine: 100x faster incremental builds (microseconds).
Step 1: Setup (v4)
Tailwind CSS was created because writing custom CSS for every project leads to inconsistent designs, bloated stylesheets, and the constant struggle of naming classes. Instead of writing CSS, you compose utility classes directly in HTML, getting a consistent design system with zero unused styles in production. Tailwind v4 is a ground-up rewrite: configuration moves to CSS (@theme {}), content detection is automatic, the engine is 10x faster, and it uses modern CSS features (cascade layers, P3 colors) natively.
# Install
npm install tailwindcss @tailwindcss/postcss
# Or with Vite (recommended)
npm install tailwindcss @tailwindcss/vite
/* app.css — That's it! One line to start */
@import "tailwindcss";
// postcss.config.js (if using PostCSS)
export default {
plugins: ["@tailwindcss/postcss"],
};
// OR vite.config.ts (faster)
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [tailwindcss()],
});
CSS-First Configuration
/* No more tailwind.config.js — configure in CSS */
@import "tailwindcss";
@theme {
/* Custom colors */
--color-brand-50: oklch(0.97 0.01 250);
--color-brand-500: oklch(0.55 0.2 250);
--color-brand-900: oklch(0.25 0.1 250);
/* Custom fonts */
--font-display: "Cal Sans", sans-serif;
--font-body: "Inter", sans-serif;
/* Custom breakpoints */
--breakpoint-xs: 475px;
--breakpoint-3xl: 1920px;
/* Custom spacing */
--spacing: 0.25rem; /* Base unit — w-4 = 1rem */
/* Custom animations */
--animate-slide-in: slide-in 0.3s ease-out;
}
@keyframes slide-in {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
Step 2: Layout & Flexbox/Grid
Flexbox and Grid are the two modern CSS layout systems, and Tailwind makes them accessible without memorizing CSS property names. Flexbox handles one-dimensional layouts (rows or columns), Grid handles two-dimensional layouts (rows AND columns simultaneously). Before these existed, developers used floats and clearfixes — fragile hacks that broke constantly. Tailwind's utility classes map directly to these CSS properties, making complex layouts achievable by reading class names instead of debugging nested CSS.
Flexbox
<!-- Row with space between -->
<div class="flex items-center justify-between gap-4">
<img class="size-10 rounded-full" />
<div class="flex-1">
<p class="font-medium">John Doe</p>
<p class="text-sm text-gray-500">Developer</p>
</div>
<button class="rounded-lg bg-brand-500 px-4 py-2 text-white">Follow</button>
</div>
<!-- Center anything -->
<div class="flex min-h-screen items-center justify-center">
<div>Perfectly centered</div>
</div>
<!-- Responsive: stack on mobile, row on desktop -->
<div class="flex flex-col gap-4 md:flex-row">
<aside class="w-full md:w-64">Sidebar</aside>
<main class="flex-1">Content</main>
</div>
Grid
<!-- Responsive grid -->
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
<div class="rounded-xl border p-4">Card 1</div>
<div class="rounded-xl border p-4">Card 2</div>
<div class="rounded-xl border p-4">Card 3</div>
<div class="rounded-xl border p-4">Card 4</div>
</div>
<!-- Complex grid layout -->
<div class="grid grid-cols-12 gap-4">
<header class="col-span-12">Header</header>
<aside class="col-span-3">Sidebar</aside>
<main class="col-span-6">Main Content</main>
<aside class="col-span-3">Right Panel</aside>
</div>
<!-- Auto-fit (as many columns as fit) -->
<div class="grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-4">
<!-- Cards auto-wrap based on available space -->
</div>
Step 3: Responsive Design
Tailwind's responsive design uses mobile-first breakpoints: styles apply from the specified breakpoint and up. This approach was adopted because mobile-first forces you to design for the constrained case first (small screens) and progressively enhance for larger screens, resulting in better UX and simpler CSS. Instead of writing media queries in separate stylesheet blocks, you prefix any utility with a breakpoint (md:, lg:) right in your HTML, making responsive behavior visible and co-located with the element.
Breakpoints (Mobile-First)
<!-- Mobile first: start small, add at breakpoints -->
<div class="
text-sm /* Mobile (default) */
md:text-base /* ≥768px */
lg:text-lg /* ≥1024px */
xl:text-xl /* ≥1280px */
">
Responsive text
</div>
<!-- Hide/show at breakpoints -->
<nav class="hidden md:block">Desktop nav</nav>
<button class="md:hidden">Mobile menu ☰</button>
Container Queries (v4 — built-in!)
<!-- Parent declares itself as container -->
<div class="@container">
<!-- Children respond to container width, not viewport -->
<div class="flex flex-col @sm:flex-row @lg:grid @lg:grid-cols-3">
<div>Responds to parent's width!</div>
</div>
</div>
<!-- Named containers -->
<div class="@container/sidebar">
<p class="@sm/sidebar:text-lg">Responds to sidebar container</p>
</div>
<!-- Max-width container queries -->
<div class="@container">
<div class="grid grid-cols-3 @max-md:grid-cols-1">
<!-- Switches to 1 column when container is narrow -->
</div>
</div>
Step 4: Colors, Typography & Spacing
Tailwind's design token system (colors, font sizes, spacing scale) solves the "every developer picks different values" problem. Without a constrained scale, you get padding: 13px in one place and padding: 15px in another — visually inconsistent. Tailwind's spacing scale (4px increments), color palette (carefully crafted for accessibility), and typography scale create visual harmony automatically. v4 adds P3 wide-gamut colors for displays that support them, making designs more vibrant on modern screens.
Colors (P3 Gamut in v4)
<!-- Named colors -->
<div class="bg-blue-500 text-white">Blue background</div>
<div class="bg-blue-500/50">50% opacity blue (color-mix)</div>
<!-- Dark mode -->
<div class="bg-white text-gray-900 dark:bg-gray-900 dark:text-white">
Auto dark mode
</div>
<!-- Gradients -->
<div class="bg-linear-to-r from-purple-500 via-pink-500 to-red-500">
Linear gradient
</div>
<div class="bg-linear-45 from-blue-500 to-green-500">
45-degree gradient (v4)
</div>
<div class="bg-radial from-white to-blue-500">
Radial gradient (v4)
</div>
Typography
<!-- Text utilities -->
<h1 class="text-4xl font-bold tracking-tight text-gray-900">
Heading
</h1>
<p class="text-base leading-7 text-gray-600">
Body text with comfortable line height
</p>
<p class="line-clamp-3">
This text will be truncated to 3 lines with ellipsis...
</p>
<!-- Prose (typography plugin) -->
<article class="prose prose-lg dark:prose-invert max-w-none">
<!-- Rendered markdown gets beautiful typography -->
</article>
Spacing System
<!-- Tailwind v4: any number works (computed from --spacing) -->
<div class="p-4"> <!-- padding: 1rem (4 × 0.25rem) -->
<div class="m-6"> <!-- margin: 1.5rem -->
<div class="gap-8"> <!-- gap: 2rem -->
<div class="w-72"> <!-- width: 18rem -->
<div class="h-screen"> <!-- height: 100vh -->
<!-- Arbitrary values still work -->
<div class="p-[13px]">Exact pixel value</div>
Step 5: Animations & Transitions
Animations and transitions add polish that separates professional UIs from amateur ones — hover states that fade smoothly, elements that slide in on scroll, loading spinners that pulse. Tailwind provides pre-built animation utilities (animate-spin, animate-pulse, animate-bounce) and transition utilities that handle timing functions and durations. These save you from writing @keyframes declarations and transition properties manually while keeping animations performant (GPU-accelerated transforms and opacity).
Transitions
<!-- Hover with smooth transition -->
<button class="
bg-blue-500 text-white rounded-lg px-4 py-2
transition-all duration-200 ease-out
hover:bg-blue-600 hover:scale-105 hover:shadow-lg
active:scale-95
">
Click me
</button>
<!-- Group hover -->
<div class="group rounded-xl border p-4 transition hover:border-blue-500">
<h3 class="transition group-hover:text-blue-500">Title</h3>
<p class="text-gray-500">Description</p>
<span class="transition-transform group-hover:translate-x-1">→</span>
</div>
Animations
<!-- Built-in animations -->
<div class="animate-spin">⟳</div>
<div class="animate-bounce">↕</div>
<div class="animate-pulse">Loading skeleton</div>
<!-- @starting-style (v4) — animate on first display -->
<div popover class="
opacity-0 transition-all duration-300
starting:open:opacity-0 starting:open:scale-95
open:opacity-100 open:scale-100
">
Animates in when shown!
</div>
Step 6: Common Component Patterns
These patterns are the building blocks you'll copy-paste and adapt in every project: cards, buttons, badges, navigation bars, form inputs. They demonstrate how Tailwind utilities compose into production-quality components without any custom CSS. Each pattern includes dark mode support, hover/focus states, and responsive considerations. Rather than reaching for a component library (with its bundle size and customization limitations), these patterns give you full control while maintaining consistency.
Card
<div class="rounded-xl border bg-white p-6 shadow-sm transition hover:shadow-md dark:bg-gray-900 dark:border-gray-800">
<img class="aspect-video w-full rounded-lg object-cover" src="..." />
<h3 class="mt-4 text-lg font-semibold">Card Title</h3>
<p class="mt-2 text-sm text-gray-500 line-clamp-2">Description...</p>
<div class="mt-4 flex items-center gap-2">
<span class="rounded-full bg-blue-100 px-2 py-0.5 text-xs text-blue-700">Tag</span>
</div>
</div>
Navigation Bar
<nav class="sticky top-0 z-50 border-b bg-white/80 backdrop-blur-lg dark:bg-gray-900/80">
<div class="mx-auto flex h-16 max-w-7xl items-center justify-between px-4">
<a href="/" class="text-xl font-bold">Logo</a>
<div class="hidden items-center gap-6 md:flex">
<a class="text-sm text-gray-600 hover:text-gray-900 transition">Home</a>
<a class="text-sm text-gray-600 hover:text-gray-900 transition">Blog</a>
<button class="rounded-lg bg-black px-4 py-2 text-sm text-white">Sign up</button>
</div>
</div>
</nav>
Input with Label
<div class="space-y-2">
<label class="text-sm font-medium text-gray-700" for="email">Email</label>
<input
id="email"
type="email"
class="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm
placeholder:text-gray-400
focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20
disabled:cursor-not-allowed disabled:opacity-50"
placeholder="you@example.com"
/>
<p class="text-xs text-red-500">Email is required</p>
</div>
Step 7: v4 New Features Summary
Tailwind v4 is the biggest update since the framework's creation: configuration moves from JavaScript to CSS (@theme {} blocks), content paths are auto-detected (no more manual config), the engine uses Rust (Lightning CSS) for 10x faster builds, and modern CSS features (cascade layers, color-mix(), container queries) are supported natively. Understanding what changed helps you migrate existing projects and take advantage of features that weren't possible in v3.
| Feature | v3 | v4 |
|---|---|---|
| Config | tailwind.config.js |
@theme {} in CSS |
| Content paths | Manual content: [...] |
Auto-detected |
| Container queries | @tailwindcss/container-queries plugin |
Built-in (@container, @sm:) |
| 3D transforms | Not available | rotate-x-*, rotate-y-*, scale-z-* |
| Gradients | Linear only, limited | Linear angles, radial, conic, interpolation modes |
@starting-style |
Not available | starting: variant |
| Colors | sRGB | OKLCH (P3 gamut) |
| Performance | Fast | 5x faster full, 100x faster incremental |
not-* variant |
Not available | not-hover:, not-supports-*: |
in-* variant |
group-* + class |
in-* (implicit group) |
Interview Questions
-
How is Tailwind v4 different from v3?
- CSS-first configuration (
@theme {}replaces JS config). Auto content detection. Built-in container queries. Oxide engine (100x faster incremental). OKLCH colors. No moretailwind.config.jsneeded.
- CSS-first configuration (
-
What's the mobile-first approach?
- Default styles apply to mobile. Breakpoint prefixes (
md:,lg:) add styles at larger sizes. Start with the smallest screen, layer complexity upward.
- Default styles apply to mobile. Breakpoint prefixes (
-
Container queries vs media queries?
- Media queries respond to viewport width. Container queries respond to parent element width. Container queries are better for reusable components that may appear in different layout contexts (sidebar vs main content).
-
How do you handle dark mode?
- Use
dark:variant on utilities. Tailwind detects viaprefers-color-schemeorclassstrategy (add.darkclass to html for manual toggle).
- Use