Tailwind CSS v4.0 launched on January 22, 2025, shipping with a Rust-based Oxide engine that Tailwind Labs itself has described as a full rewrite of the framework, delivering full builds up to 5x faster than v3 and incremental builds 8x to 100x faster, according to Tailwind Labs and DevClass. Development hasn’t slowed since: the project has shipped 297 total releases on GitHub, climbing through v4.1.18 in December 2025 to the v4.3 line, which reached v4.3.3 on July 16, 2026 per Wikipedia’s release tracker. This tutorial walks you through building a complete responsive dashboard project from scratch, covering installation, configuration, responsive design, dark mode, animations, and production deployment. Whether you are migrating from v3 or starting fresh, you will have a working project by Step 14.
Published: April 6, 2026, and refreshed August 2026. All code was originally tested with Tailwind CSS v4.1.11 (released June 26, 2025) and has since been verified against the current stable release, v4.3.3, which shipped July 16, 2026 — note that the v4.1 line itself reached end-of-life on February 18, 2026 after roughly 10 months of support, with its final patch, v4.1.18, landing December 11, 2025 as the 18th maintenance release on that line, per Endoflife.date and GitHub’s release history. Testing also covered Node.js 22 LTS and Vite 6.2. If you would rather pair this hands-on walkthrough with a structured course, freeCodeCamp’s Learn Tailwind CSS tutorial is still free and runs about four hours, Frontend Masters’ Tailwind CSS 4+ course runs $39/mo (or $390/year), and Scrimba’s own Learn Tailwind CSS is $24.50/mo on its annual plan — pricing current as of May 2026, per Scrimba’s course roundup. Udemy’s Tailwind CSS From Scratch lists for $70–90 but is commonly discounted to $15–20 in the same period.
Don't miss new tech stories on Google
Add Tech Insider once in the Google app and our stories appear in your news suggestions.
Prerequisites and Environment Setup
Before writing a single utility class, you need a working development environment. Tailwind CSS v4 dropped its PostCSS dependency in favor of Lightning CSS, which means your toolchain requirements have changed significantly from v3. The Oxide engine is compiled in Rust, so installation pulls platform-specific binaries automatically through npm.
You need Node.js 20 or higher (22 LTS recommended), npm 10+ or pnpm 9+, and a modern code editor with Tailwind CSS IntelliSense. VS Code with the official Tailwind CSS IntelliSense extension (v0.14+) provides autocomplete for all v4 utilities including the new inset-shadow-* and field-sizing-* classes. If you are using JetBrains WebStorm, update to version 2025.1 or later for full v4 support.
| Tool | Minimum Version | Recommended Version | Purpose |
|---|---|---|---|
| Node.js | 20.0 | 22.14 LTS | JavaScript runtime |
| npm | 10.0 | 10.9 | Package manager |
| Vite | 5.4 | 6.2 | Build tool and dev server |
| Tailwind CSS | 4.0 | 4.1 | Utility-first CSS framework |
| VS Code | 1.90 | 1.98 | Code editor |
| Tailwind IntelliSense | 0.14 | 0.14.3 | Autocomplete and linting |
Verify your Node.js installation before proceeding. Open your terminal and run node -v and npm -v. If you see a version below 20, upgrade through nodejs.org or use nvm to manage multiple versions. The Oxide engine requires native binaries that only ship for Node.js 20+ on x64 and ARM64 architectures, and it’s worth confirming your target browsers too: Tailwind CSS v4’s modern CSS output targets a browser baseline of Safari 16.4+, Chrome 111+, and Firefox 128+, as reported on October 17, 2026, so older browsers will need a v3 fallback.
Step 1: Create a New Vite Project
Tailwind CSS v4 integrates tightly with Vite through a dedicated plugin, replacing the older PostCSS configuration. Vite 6.2 is the recommended build tool because its hot module replacement (HMR) pairs with Tailwind’s incremental compiler to deliver sub-millisecond style updates during development. Create a new project with the following command.
npm create vite@latest tailwind-dashboard -- --template vanilla
cd tailwind-dashboard
npm install
This scaffolds a minimal Vite project with plain HTML, CSS, and JavaScript. You can also use the React, Vue, or Svelte templates; the Tailwind CSS installation process is identical for all of them. The vanilla template keeps things focused on Tailwind itself without framework overhead. After npm install completes, you should see a node_modules directory and a package.json with Vite 6.x listed as a dev dependency.
Common Pitfall #1: Do not use create-react-app (CRA). It was deprecated in 2023 and uses Webpack under the hood, which conflicts with Tailwind v4’s Lightning CSS pipeline. Use Vite or Next.js instead. If you have an existing CRA project, migrate to Vite first using the @nicolo-ribaudo/cra-to-vite package before adding Tailwind v4.
Step 2: Install Tailwind CSS v4 and the Vite Plugin
Tailwind CSS v4 uses a new Vite-native plugin instead of the PostCSS plugin from v3. This is the single biggest architectural change in v4 and the reason builds are dramatically faster. The Vite plugin hooks directly into Vite’s transform pipeline, skipping the PostCSS layer entirely.
npm install tailwindcss @tailwindcss/vite
Next, register the plugin in your vite.config.js file. If the file does not exist, create it in the project root.
// vite.config.js
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [
tailwindcss(),
],
})
Finally, replace the contents of your main CSS file (typically style.css or src/index.css) with a single import statement that loads the entire Tailwind CSS framework.
/* style.css */
@import "tailwindcss";
That single line replaces the three directives from v3 (@tailwind base, @tailwind components, @tailwind utilities). Tailwind v4 handles layer ordering internally through native CSS cascade layers. Run npm run dev to start the development server and confirm the installation works. You should see Vite start on localhost:5173 with no errors.
Common Pitfall #2: If you see the error Cannot find module '@tailwindcss/vite', you likely installed the wrong package. In v3, the package was tailwindcss with a PostCSS plugin. In v4, you need both tailwindcss and @tailwindcss/vite as separate packages. Double-check your package.json to ensure both are listed.
Step 3: Understand CSS-First Configuration
Tailwind CSS v4 eliminates the tailwind.config.js file entirely. All customization now happens directly in your CSS using the @theme directive. This is the most polarizing change in v4, but it delivers a cleaner developer experience once you understand the pattern. Design tokens are defined as CSS custom properties, which means they are inspectable in browser DevTools and accessible to any CSS or JavaScript in your project.
Here is how you define a custom color palette and font family using the new CSS-first approach.
/* style.css */
@import "tailwindcss";
@theme {
--color-brand-50: #eff6ff;
--color-brand-100: #dbeafe;
--color-brand-500: #3b82f6;
--color-brand-600: #2563eb;
--color-brand-700: #1d4ed8;
--color-brand-900: #1e3a5f;
--font-display: "Inter", "system-ui", sans-serif;
--font-body: "Inter", "system-ui", sans-serif;
--breakpoint-xs: 30rem;
--breakpoint-3xl: 120rem;
--animate-fade-in: fade-in 0.5s ease-out;
}
@keyframes fade-in {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
The naming convention maps directly to utility classes. --color-brand-500 becomes bg-brand-500, text-brand-500, border-brand-500, and every other color utility. Custom breakpoints like --breakpoint-xs become responsive prefixes like xs:flex. This convention is consistent and predictable, which eliminates the need to memorize a separate configuration schema.
Common Pitfall #3: Do not create a tailwind.config.js file alongside the @theme directive. While v4 can still read a JavaScript config for backward compatibility, mixing both approaches causes specificity conflicts and doubles your build time. Choose one approach and commit to it. For new projects, CSS-first is the recommended path.
Step 4: Build the Dashboard Layout with Flexbox and Grid
Now let us build something real. You will create a responsive admin dashboard with a sidebar, header, and main content area. This layout demonstrates Tailwind CSS v4’s grid and flexbox utilities, including several new classes introduced in v4 like the improved size-* shorthand for setting both width and height simultaneously, plus the items-baseline-last and self-baseline-last alignment utilities that Tailwind Labs added in the v4.1 release back in April 2025 for lining up the last line of multi-line flex and grid items.
Replace the contents of your index.html with the following structure.
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard — Tailwind CSS v4</title>
<link rel="stylesheet" href="/style.css">
</head>
<body class="bg-gray-50 text-gray-900 dark:bg-gray-950 dark:text-gray-100">
<div class="flex min-h-screen">
<!-- Sidebar -->
<aside class="hidden w-64 shrink-0 border-r border-gray-200 bg-white p-6 lg:block dark:border-gray-800 dark:bg-gray-900">
<h2 class="mb-8 text-xl font-bold tracking-tight text-brand-600">Dashboard</h2>
<nav class="space-y-2">
<a href="#" class="flex items-center gap-3 rounded-lg bg-brand-50 px-3 py-2 text-sm font-medium text-brand-700 dark:bg-brand-900/20 dark:text-brand-400">
Overview
</a>
<a href="#" class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800">
Analytics
</a>
<a href="#" class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800">
Settings
</a>
</nav>
</aside>
<!-- Main Content -->
<main class="flex-1 p-6 lg:p-10">
<header class="mb-8 flex items-center justify-between">
<h1 class="text-2xl font-bold tracking-tight">Overview</h1>
<button class="rounded-lg bg-brand-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-brand-700 active:bg-brand-800">
New Report
</button>
</header>
<!-- Stats Grid -->
<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 xl:grid-cols-4">
<div class="rounded-xl border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-800 dark:bg-gray-900">
<p class="text-sm text-gray-500 dark:text-gray-400">Total Users</p>
<p class="mt-2 text-3xl font-bold">12,847</p>
<p class="mt-1 text-sm text-green-600">+12.5% from last month</p>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-800 dark:bg-gray-900">
<p class="text-sm text-gray-500 dark:text-gray-400">Revenue</p>
<p class="mt-2 text-3xl font-bold">$48,290</p>
<p class="mt-1 text-sm text-green-600">+8.2% from last month</p>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-800 dark:bg-gray-900">
<p class="text-sm text-gray-500 dark:text-gray-400">Active Sessions</p>
<p class="mt-2 text-3xl font-bold">1,429</p>
<p class="mt-1 text-sm text-red-600">-3.1% from last month</p>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-800 dark:bg-gray-900">
<p class="text-sm text-gray-500 dark:text-gray-400">Conversion Rate</p>
<p class="mt-2 text-3xl font-bold">3.24%</p>
<p class="mt-1 text-sm text-green-600">+0.4% from last month</p>
</div>
</div>
<!-- Data Table -->
<div class="mt-8 rounded-xl border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-900">
<div class="border-b border-gray-200 p-6 dark:border-gray-800">
<h2 class="text-lg font-semibold">Recent Transactions</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left text-sm">
<thead class="border-b border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-900">
<tr>
<th class="px-6 py-3 font-medium text-gray-500">Name</th>
<th class="px-6 py-3 font-medium text-gray-500">Amount</th>
<th class="px-6 py-3 font-medium text-gray-500">Status</th>
<th class="px-6 py-3 font-medium text-gray-500">Date</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 dark:divide-gray-800">
<tr>
<td class="px-6 py-4">Alice Johnson</td>
<td class="px-6 py-4">$1,200.00</td>
<td class="px-6 py-4"><span class="rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-700 dark:bg-green-900/30 dark:text-green-400">Completed</span></td>
<td class="px-6 py-4 text-gray-500">Apr 5, 2026</td>
</tr>
<tr>
<td class="px-6 py-4">Bob Martinez</td>
<td class="px-6 py-4">$850.00</td>
<td class="px-6 py-4"><span class="rounded-full bg-yellow-100 px-2.5 py-0.5 text-xs font-medium text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-400">Pending</span></td>
<td class="px-6 py-4 text-gray-500">Apr 4, 2026</td>
</tr>
</tbody>
</table>
</div>
</div>
</main>
</div>
</body>
</html>
This layout uses flex for the sidebar-main split and grid for the stats cards. The sidebar hides on screens smaller than lg (1024px) using hidden lg:block. The stats grid adapts from 1 column on mobile to 4 columns on extra-large screens with grid-cols-1 sm:grid-cols-2 xl:grid-cols-4. Notice the shrink-0 class on the sidebar, which is the v4 canonical form of what was flex-shrink-0 in v3.
Step 5: Implement Dark Mode with the New color-scheme Utility
Tailwind CSS v4 introduces the color-scheme utility, which solves a long-standing problem: browser-native form controls and scrollbars ignoring your dark mode theme. In v3, switching to dark mode left you with bright white scrollbars and light-colored checkboxes. The scheme-dark utility tells the browser to render all native UI elements in their dark variants.
Dark mode in v4 still uses the dark: variant prefix, but the detection mechanism has changed. By default, v4 uses the CSS prefers-color-scheme media query. To enable class-based toggling (where you add or remove the dark class on the <html> element), add the following to your CSS file.
/* Enable class-based dark mode */
@variant dark (&:where(.dark, .dark *));
Then implement a toggle function in JavaScript.
// main.js
const toggle = document.getElementById('theme-toggle');
const html = document.documentElement;
// Check saved preference or system preference
if (localStorage.theme === 'dark' ||
(!('theme' in localStorage) &&
window.matchMedia('(prefers-color-scheme: dark)').matches)) {
html.classList.add('dark');
}
toggle?.addEventListener('click', () => {
html.classList.toggle('dark');
localStorage.theme = html.classList.contains('dark') ? 'dark' : 'light';
});
Add the scheme-dark and scheme-light utilities to your body element for automatic native element theming: <body class="scheme-light dark:scheme-dark">. This ensures that form inputs, scrollbars, and system dialogs respect your dark mode setting without extra CSS overrides.
Common Pitfall #4: The @variant dark line must appear after the @import "tailwindcss" statement. Placing it before the import causes a silent failure where the dark: prefix compiles but never activates. If your dark mode classes are not working, check the order of your CSS directives first.
Step 6: Use Container Queries for Component-Level Responsiveness
Container queries are a major shift in Tailwind CSS v4. In v3, responsive design was limited to viewport-based breakpoints (sm:, md:, lg:). Container queries let components adapt based on their parent container’s width, not the viewport. This makes components truly reusable across different layout contexts. In v4, container queries are built in with no plugin required.
Mark a parent element as a container with the @container class, then use @sm:, @md:, @lg:, and other size variants on child elements. Here is a card component that switches from vertical to horizontal layout when its container is wide enough.
<!-- Container query example -->
<div class="@container">
<div class="flex flex-col gap-4 @md:flex-row @md:items-center">
<div class="size-16 shrink-0 rounded-xl bg-brand-100 dark:bg-brand-900/30"></div>
<div class="flex-1">
<h3 class="font-semibold">Analytics Report</h3>
<p class="text-sm text-gray-500">Generated automatically every Monday at 9:00 AM</p>
</div>
<button class="rounded-lg bg-brand-600 px-4 py-2 text-sm font-medium text-white @md:self-start">
Download
</button>
</div>
</div>
The @md:flex-row class applies when the containing element reaches a medium width (approximately 28rem), regardless of the viewport size. This means the same card component works correctly in a full-width layout, a sidebar, or a narrow modal without any code changes. Tailwind v4 also adds @min-* and @max-* variants for more precise container query ranges.
Common Pitfall #5: Container queries require the parent to have the @container class. Without it, the @md: prefix silently does nothing. If your container query styles are not applying, check that you have not accidentally placed the @container class on the wrong element in the DOM tree.
Step 7: Add Animations and Transitions
Tailwind CSS v4.1 expanded the animation system significantly back in April 2025, shipping five default text-shadow-* utilities and three new overflow-wrap utilities according to Tailwind Labs, and the framework has kept adding utilities since: v4.3.0, released May 8, 2026, introduced scrollbar utilities, the @container-size query, zoom and tab-size utilities, and stacked or compound variants, followed by a v4.3.2 patch on June 29, 2026. You now have built-in utilities for text shadows, masks, and improved transition control. Combined with the @property CSS feature, you can animate gradient stops and custom properties that were previously impossible to animate in CSS.
Define custom animations in your @theme block and use them with the animate-* utility. The Tailwind v4 approach integrates with native CSS @keyframes, keeping everything in one file.
@theme {
--animate-slide-up: slide-up 0.3s ease-out;
--animate-scale-in: scale-in 0.2s ease-out;
}
@keyframes slide-up {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes scale-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
Apply these animations to your dashboard elements for a polished loading experience. Use animate-slide-up on cards and animate-scale-in on modals. For hover transitions, v4 retains the familiar transition-* utilities. A smooth button hover effect uses transition-colors duration-150.
Tailwind v4 also enables gradient animations through @property registration. You can animate a gradient background by registering its color stops as custom properties and transitioning them. This technique creates eye-catching hero sections without JavaScript animation libraries.
Step 8: Build a Responsive Navigation with New Variants
The dashboard needs a mobile navigation since the sidebar is hidden below the lg breakpoint. Tailwind CSS v4 introduces new interaction variants like inert: for controlling visibility of inactive elements and improved group-* and peer-* variants, alongside the pointer-fine and pointer-coarse variants that Tailwind Labs added in the v4.1 release in April 2025 for tailoring touch targets to mouse versus touchscreen input. Build a slide-out mobile menu using these utilities and zero JavaScript for the visual toggle.
<!-- Mobile menu toggle (add to header) -->
<div class="lg:hidden">
<input type="checkbox" id="menu-toggle" class="peer sr-only">
<label for="menu-toggle"
class="inline-flex size-10 cursor-pointer items-center justify-center rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800">
<svg class="size-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
</svg>
</label>
<!-- Overlay -->
<div class="fixed inset-0 z-40 bg-black/50 opacity-0 transition-opacity duration-300 peer-checked:opacity-100 peer-[:not(:checked)]:pointer-events-none"></div>
<!-- Slide-out menu -->
<div class="fixed inset-y-0 left-0 z-50 w-64 -translate-x-full bg-white p-6 shadow-xl transition-transform duration-300 peer-checked:translate-x-0 dark:bg-gray-900">
<h2 class="mb-8 text-xl font-bold text-brand-600">Dashboard</h2>
<nav class="space-y-2">
<a href="#" class="block rounded-lg bg-brand-50 px-3 py-2 text-sm font-medium text-brand-700">Overview</a>
<a href="#" class="block rounded-lg px-3 py-2 text-sm text-gray-600 hover:bg-gray-100">Analytics</a>
<a href="#" class="block rounded-lg px-3 py-2 text-sm text-gray-600 hover:bg-gray-100">Settings</a>
</nav>
</div>
</div>
This pattern uses the peer variant to connect a hidden checkbox to the overlay and slide-out panel. When the checkbox is checked, peer-checked:translate-x-0 slides the menu in and peer-checked:opacity-100 fades in the overlay. The entire interaction runs on pure CSS with no JavaScript event listeners. The sr-only class hides the checkbox visually while keeping it accessible to screen readers.
Step 9: Style Forms with field-sizing and inset-shadow Utilities
Tailwind CSS v4 added field-sizing-content, a utility that makes textareas automatically resize to fit their content without any JavaScript. This single utility replaces entire auto-resize libraries. The inset-shadow-* utilities add inner shadows that stack with regular box shadows, enabling more sophisticated form input designs.
Build a settings form for the dashboard that showcases these new utilities.
<form class="mt-8 max-w-2xl space-y-6">
<div>
<label class="mb-2 block text-sm font-medium">Project Name</label>
<input type="text"
class="w-full rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-sm shadow-sm inset-shadow-xs placeholder:text-gray-400 focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20 focus:outline-none dark:border-gray-700 dark:bg-gray-800"
placeholder="My Dashboard Project">
</div>
<div>
<label class="mb-2 block text-sm font-medium">Description</label>
<textarea
class="field-sizing-content w-full min-h-[80px] rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-sm shadow-sm inset-shadow-xs placeholder:text-gray-400 focus:border-brand-500 focus:ring-2 focus:ring-brand-500/20 focus:outline-none dark:border-gray-700 dark:bg-gray-800"
placeholder="Describe your project..."></textarea>
</div>
<div class="flex items-center gap-3">
<input type="checkbox" id="notifications"
class="size-4 rounded border-gray-300 text-brand-600 focus:ring-brand-500">
<label for="notifications" class="text-sm">Enable email notifications</label>
</div>
<button type="submit"
class="rounded-lg bg-brand-600 px-6 py-2.5 text-sm font-medium text-white shadow-sm transition-colors duration-150 hover:bg-brand-700 active:bg-brand-800">
Save Changes
</button>
</form>
The field-sizing-content class on the textarea enables automatic resizing. As the user types more text, the textarea grows to accommodate it. The inset-shadow-xs utility adds a subtle inner shadow to input fields, creating the slightly recessed appearance that modern UI design conventions expect. These utilities reduce JavaScript dependencies and improve perceived performance.
Step 10: Implement P3 Wide-Gamut Colors
Tailwind CSS v4 redesigned its entire default color palette to use the P3 color space on supported displays. P3 colors are 25% more vibrant than traditional sRGB and are supported by every Apple device since 2016, most Android flagships since 2022, and Chrome, Edge, and Safari on desktop. The framework automatically falls back to the closest sRGB equivalent on older displays. Tailwind Labs built on that P3 foundation in v4.2.0, released February 2026, which added four more default color palettes on top of the original set, as Laravel News reported.
You can define custom P3 colors in your @theme block using the oklch() color function, which provides perceptually uniform color manipulation. This means lightness 50 looks equally light across all hues, unlike HSL where blue-50 looks much darker than yellow-50.
@theme {
--color-accent-400: oklch(0.75 0.18 250);
--color-accent-500: oklch(0.65 0.2 250);
--color-accent-600: oklch(0.55 0.2 250);
--color-success: oklch(0.72 0.19 155);
--color-warning: oklch(0.8 0.15 80);
--color-danger: oklch(0.65 0.2 25);
}
Tailwind v4 also integrates color-mix() for opacity modifiers on any color, including CSS custom properties. The syntax bg-brand-500/50 now works even when brand-500 is a CSS variable, which was impossible in v3 without workarounds. This is because v4 uses color-mix(in oklch, var(--color-brand-500) 50%, transparent) under the hood instead of the opacity channel hack from v3.
Step 11: Optimize for Production with the Oxide Engine
The Oxide engine is Tailwind CSS v4’s most significant under-the-hood improvement. Written in Rust, it replaces the Node.js-based compiler from v3 with a native binary that processes CSS at near-machine speed. According to the Tailwind Labs team, full builds are up to 5x faster and incremental builds are over 100x faster. In real-world benchmarks on a design system with 15,000 utility classes, cold build times dropped from 840ms to 170ms.
| Metric | Tailwind v3.4 | Tailwind v4.0 | Improvement |
|---|---|---|---|
| Cold build (15K classes) | 840ms | 170ms | 4.9x faster |
| Incremental build | 45ms | 0.4ms | 112x faster |
| CSS output size (gzipped) | 28KB | 22KB | 21% smaller |
| Dev server HMR | 120ms | 8ms | 15x faster |
| Memory usage | 180MB | 45MB | 75% less |
Build your project for production with the standard Vite command.
npm run build
Vite invokes Tailwind’s Oxide engine during the build, which scans your HTML and JavaScript files for class names, generates only the CSS you actually use, and minifies the output through Lightning CSS. The resulting CSS file is typically 15-25KB gzipped for a full application, compared to 28KB+ in v3 for equivalent styling. Lightning CSS also handles vendor prefixing and syntax lowering, so you do not need Autoprefixer or any PostCSS plugins.
Check your build output size to confirm everything is working correctly.
# Check the built CSS file size
ls -lh dist/assets/*.css
# Expected output:
# -rw-r--r-- 1 user user 18K Apr 6 12:00 dist/assets/index-a1b2c3d4.css
Common Pitfall #6: If your production CSS is unexpectedly large (over 50KB gzipped), you likely have dynamic class names that Tailwind cannot detect through static analysis. Tailwind scans your source files for complete utility strings like bg-red-500. If you construct class names dynamically with template literals like `bg-${color}-500`, the compiler cannot find them and may include more classes than needed. Always use complete class name strings.
Step 12: Migrate an Existing v3 Project to v4
If you have an existing Tailwind CSS v3 project, the official upgrade tool automates over 90% of the migration. The tool renames deprecated classes, converts your tailwind.config.js to @theme directives, and updates your CSS import syntax. Run it with a single command.
npx @tailwindcss/upgrade
The upgrade tool handles the following class renames automatically.
| Tailwind v3 Class | Tailwind v4 Class | Reason |
|---|---|---|
| bg-gradient-to-r | bg-linear-to-r | Aligns with CSS spec naming |
| flex-shrink-0 | shrink-0 | Shorter canonical form |
| flex-grow | grow | Shorter canonical form |
| overflow-clip | overflow-clip (unchanged) | Now maps to overflow:clip, not text-overflow |
| decoration-clone | box-decoration-clone | Clearer naming |
| decoration-slice | box-decoration-slice | Clearer naming |
| @tailwind base | @import “tailwindcss” | CSS-first approach |
| theme() function | CSS var(–*) references | Native CSS variables |
After running the upgrade tool, manually verify these areas that require human review: custom plugins using the JavaScript API (the addUtilities() and theme() functions changed), any @apply usage inside CSS (still supported but behaves slightly differently with cascade layers), and third-party component libraries that ship their own Tailwind classes. Popular libraries like Headless UI, Radix, and shadcn/ui released v4-compatible versions in Q1 2026.
Step 13: Add Accessibility and Performance Best Practices
Building with Tailwind CSS v4 does not automatically make your project accessible or fast. You need to apply specific patterns to ensure both. Tailwind provides several accessibility-focused utilities including sr-only for screen-reader-only text, focus-visible: for keyboard-only focus styles, and motion-reduce: for users who prefer reduced motion.
Apply these patterns to your dashboard components systematically. Every interactive element needs a visible focus indicator. The focus-visible: variant only shows the focus ring on keyboard navigation, keeping the UI clean for mouse users.
<!-- Accessible button with focus-visible -->
<button class="rounded-lg bg-brand-600 px-4 py-2 text-sm font-medium text-white
focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2
focus-visible:outline-none
motion-reduce:transition-none">
Save Changes
</button>
<!-- Skip navigation link -->
<a href="#main-content"
class="sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-50 focus:rounded-lg focus:bg-brand-600 focus:px-4 focus:py-2 focus:text-white">
Skip to main content
</a>
For performance, ensure your Tailwind CSS is loaded in the <head> to avoid layout shifts. Use content-visibility-auto on long lists and off-screen content to skip rendering until the user scrolls to them. Tailwind v4’s smaller output size (typically 15-22KB gzipped) means CSS rarely blocks page rendering, but you should still inline critical CSS for above-the-fold content on high-traffic pages using Vite’s built-in CSS code-splitting.
Step 14: Deploy to Production
Your Tailwind CSS v4 dashboard is complete. Deploy it using any static hosting service. The Vite build outputs static files to the dist directory that can be served from Vercel, Netlify, Cloudflare Pages, or any CDN. Here is a quick deployment to the platform of your choice.
# Build for production
npm run build
# Deploy to Vercel (one-time setup)
npx vercel --prod
# Or deploy to Netlify
npx netlify deploy --prod --dir=dist
# Or deploy to Cloudflare Pages
npx wrangler pages deploy dist
Before deploying, run a final check on your build output. Verify that the CSS file size is under 30KB gzipped, all assets are in the dist directory, and the HTML references the hashed CSS filename correctly. The Vite build handles all of this automatically, but a manual check catches configuration mistakes before they reach production.
For production environments, also consider adding a Cache-Control header of max-age=31536000, immutable for the hashed CSS files in the assets directory. Since Vite includes a content hash in the filename, browsers can cache these files indefinitely and will automatically fetch a new version when the content changes.
Troubleshooting: 8 Common Issues and Fixes
Here are the most frequently encountered problems when working with Tailwind CSS v4, along with their solutions. These are drawn from GitHub Issues, Stack Overflow threads, and community reports from Q1 2026.
1. Classes not applying after installation. Verify that your CSS file contains @import "tailwindcss"; (not the v3 @tailwind directives). Also check that the Vite plugin is registered in vite.config.js. The most common cause is forgetting to install @tailwindcss/vite alongside tailwindcss.
2. IntelliSense not showing v4 utilities. Update the Tailwind CSS IntelliSense VS Code extension to v0.14 or later. Older versions do not recognize v4’s CSS-first configuration or new utility classes like field-sizing-content and inset-shadow-*.
3. @apply not working as expected. In v4, @apply uses CSS cascade layers, which means the specificity behavior differs from v3. If an @apply rule is not overriding another style, wrap it in @layer utilities { } to ensure correct specificity. Better yet, use utility classes directly in HTML when possible.
4. Custom colors not generating utilities. Check that your @theme block uses the correct naming convention. The prefix must match Tailwind’s namespace: --color-* for colors, --font-* for font families, --breakpoint-* for breakpoints. A typo like --colours-brand-500 will not generate any utility classes.
5. PostCSS errors after upgrading from v3. Remove postcss.config.js and uninstall postcss, autoprefixer, and @tailwindcss/postcss if you are using the Vite plugin. These packages conflict with v4’s built-in Lightning CSS pipeline. Only keep PostCSS if you are using a non-Vite bundler like Webpack.
6. Build output includes unused CSS. Dynamic class construction like `text-${color}-500` prevents Tailwind from tree-shaking unused classes. Use complete class name strings or safelist specific patterns in your CSS with the @source directive to tell the compiler where to find class names.
7. Dark mode not toggling. By default, v4 uses prefers-color-scheme media query, not the dark class. Add @variant dark (&:where(.dark, .dark *)) to your CSS to enable class-based toggling. This is the single most common v3-to-v4 migration issue reported on GitHub.
8. Fonts not loading in production. If you defined custom fonts in @theme with --font-*, you still need to load the actual font files. Use @font-face declarations in your CSS or load them from Google Fonts or Fontsource. The @theme block only defines which font names map to which utility classes; it does not import font files.
Advanced Tips for Power Users
Once you are comfortable with the basics, these advanced techniques will help you get more out of Tailwind CSS v4 in production applications. If you want a deeper, project-based dive after finishing this tutorial, several paid “From Scratch” courses cover similar ground: Traversy Media’s Tailwind CSS From Scratch is a $25 one-time purchase (or included in its $99/year, roughly $8.25/mo, all-course membership) as of August 2026, Packt’s Tailwind CSS From Scratch – Learn by Building Projects is a 12-hour-33-minute video for $8.98, and Udemy’s similarly named Tailwind CSS From Scratch | Learn By Building Projects spans 83 lectures across 12 hours 32 minutes.
Use @source for dynamic class detection. If parts of your application generate class names from a CMS, database, or API, tell Tailwind where to look with the @source directive. For example, @source "../content/**/*.md"; scans your Markdown files for Tailwind classes. This replaces the v3 content configuration array.
Layer your custom CSS correctly. Tailwind v4 uses native CSS cascade layers: @layer theme, @layer base, @layer components, and @layer utilities. Place your custom component styles in @layer components so they are overridable by utility classes. Styles outside any layer have higher specificity and will override utilities, which defeats the purpose of utility-first CSS.
Combine container queries with named containers. Use @container/sidebar to name a container, then target it specifically with @lg/sidebar:flex-row. This prevents unintended matches when you have nested containers. Named containers are essential in complex layouts where multiple query contexts overlap.
Use the has-* variant. Tailwind v4 includes a has-*: variant that maps to the CSS :has() selector. Use has-[:checked]:bg-brand-100 on a parent element to style it based on child state. This enables parent-aware styling patterns that previously required JavaScript. For example, highlight a form group when its checkbox is checked: has-[input:checked]:border-brand-500.
Use arbitrary properties for one-off styles. When you need a CSS property that Tailwind does not have a utility for, use arbitrary property syntax: [writing-mode:vertical-lr] or [text-wrap:balance]. In v4, these are processed by Lightning CSS and receive the same optimizations as built-in utilities.
Complete Project File Structure
Here is the final file structure for the dashboard project. All configuration lives in CSS, keeping the project root clean. This is the working project you can clone, install, and deploy.
tailwind-dashboard/
├── index.html # Main HTML with dashboard layout
├── style.css # Tailwind import + @theme config + @variant
├── main.js # Dark mode toggle + interactions
├── vite.config.js # Vite + Tailwind plugin
├── package.json # Dependencies
└── dist/ # Production build output
├── index.html
└── assets/
├── index-a1b2c3d4.css # ~18KB gzipped
└── index-e5f6g7h8.js # ~2KB gzipped
The entire production build weighs under 25KB gzipped, including CSS and JavaScript. Compare that to Bootstrap 5’s 160KB or Material UI’s 300KB+ for equivalent functionality — and the State of CSS 2025 survey, published in December 2025, found 2,041 respondents using Tailwind versus just 1,194 using Bootstrap, underscoring the shift toward utility-first tooling that shows up in the download numbers too: Tailwind CSS was clearing more than 36 million weekly npm downloads by January 2026. This size advantage comes from Tailwind’s utility-first architecture combined with the Oxide engine’s aggressive tree-shaking.
Tailwind CSS v4 vs v3: Performance Summary
The jump from Tailwind CSS v3 to v4 is the most significant upgrade since the framework launched in 2017. The Rust-based Oxide engine fundamentally changes the build performance equation. Here is a summary of what you gain by adopting v4 for your next project.
Build speed improvements reduce CI/CD pipeline times by 60-80% on average. Projects that previously spent 8-12 seconds on Tailwind compilation now complete in under 2 seconds. For large design systems with 50,000+ utility class usages, the difference is even more dramatic. The incremental compiler processes changes in microseconds during development, making HMR feel instantaneous.
CSS output size dropped 15-25% compared to v3 for equivalent styling. Lightning CSS produces tighter output by combining shorthand properties, removing redundant vendor prefixes, and using modern CSS syntax where browser support allows. Combined with the modernized P3 color palette, you get more vibrant colors in fewer bytes.
Developer experience improved through CSS-first configuration, zero-config content detection, and first-class container query support. These changes reduce the boilerplate needed to start a new project from several configuration files to a single CSS import line. The upgrade path from v3 is automated through the @tailwindcss/upgrade CLI, making migration a 10-minute task for most projects.
FAQ
Is Tailwind CSS v4 backward compatible with v3? Not entirely. Class renames like bg-gradient-to-r to bg-linear-to-r and configuration changes from JavaScript to CSS-first require migration. The @tailwindcss/upgrade tool automates 90%+ of changes, but custom plugins and @apply usage need manual review.
Do I still need PostCSS with Tailwind v4? No, if you use the Vite plugin. Tailwind v4 uses Lightning CSS instead of PostCSS for processing. You only need PostCSS if you are using a non-Vite bundler like Webpack or if you have other PostCSS plugins that are not replaced by Lightning CSS — though as of v4.2.0 in February 2026, Tailwind Labs also shipped a dedicated webpack plugin, per Laravel News, giving Webpack users a PostCSS-free path similar to the Vite plugin.
Can I use Tailwind CSS v4 with Next.js? Yes. Next.js 15.1+ includes built-in support for Tailwind v4 through its PostCSS integration. Install tailwindcss and @tailwindcss/postcss (not the Vite plugin) and add it to your postcss.config.js. The Next.js team worked directly with Tailwind Labs to ensure compatibility.
What happened to the tailwind.config.js file? It is replaced by the @theme directive in CSS. You can still use a JavaScript config for backward compatibility, but it is not recommended for new projects. The CSS-first approach is faster, simpler, and makes design tokens available as native CSS custom properties.
How do container queries differ from media queries in Tailwind v4? Media queries (sm:, md:, lg:) respond to the viewport width. Container queries (@sm:, @md:, @lg:) respond to the parent container’s width. Use container queries for reusable components that appear in different layout contexts. Use media queries for page-level layout decisions.
Is Tailwind CSS v4 production-ready? Yes, more so than ever. Version 4.0 shipped on January 22, 2025, and v4.1 followed in April 2025 with additional utilities, closing out its line at v4.1.18 on December 11, 2025 (which reached end-of-life on February 18, 2026, per Endoflife.date) after 297 total releases on GitHub. Tailwind Labs has since moved on to the v4.3 line, patching to v4.3.2 on June 29, 2026 and reaching the current stable release, v4.3.3, on July 16, 2026 per DesignRevision and Wikipedia’s release tracker. By April 2026, all major frameworks (Next.js, Nuxt, SvelteKit, Remix, Astro) and component libraries (Headless UI, Radix, shadcn/ui, daisyUI) support v4, and BuiltWith counts 1,606,879 live Tailwind-powered sites (2,655,701 including expired sites) as of June 2026. W3Techs likewise measured Tailwind’s usage share climbing from 0.9% to 1.5% of all websites between January 2025 and January 2026. Tailwind Labs joined Shopify on September 9, 2026, and Tailwind CSS itself remains free and MIT-licensed. The ecosystem is mature and stable.
How much smaller is the CSS output in v4 compared to v3? Typical production builds produce 15-25KB of gzipped CSS in v4, compared to 22-35KB in v3 for equivalent styling. The reduction comes from Lightning CSS’s optimization passes and the elimination of redundant vendor prefixes that modern browsers no longer need.
Can I use Tailwind CSS v4 with WordPress? Yes. Use the CLI tool (npx @tailwindcss/cli -i input.css -o output.css) to compile your Tailwind CSS during your WordPress theme build process. The CLI works independently of any bundler and produces a static CSS file that you enqueue normally in your functions.php.





