Tailwind CSS v4 represents a significant evolution. It uses CSS-first configuration, removes the need for a JavaScript config file, and provides full access to modern CSS features like cascade layers and native CSS nesting.
The v4 approach: CSS-first
Previous versions of Tailwind required tailwind.config.js. Version 4 uses CSS imports and at-rules instead.
Install Tailwind:
npm install tailwindcss@4
# or
pnpm add tailwindcss@4
Create a CSS entry file:
/* main.css */
@import "tailwindcss";
This single import provides all of Tailwind’s utilities, components, and base styles. There is no separate CLI command needed to generate a CSS file—Tailwind processes your CSS directly.
Theme configuration in CSS
Customize the theme using @theme:
@import "tailwindcss";
@theme {
/* Colors */
--color-brand: #0d9488;
--color-brand-dark: #0f766e;
/* Fonts */
--font-content: "Inter", system-ui, sans-serif;
--font-code: "JetBrains Mono", monospace;
/* Spacing additions */
--spacing-18: 4.5rem;
--spacing-88: 22rem;
/* Breakpoints */
--breakpoint-xl: 80rem;
--breakpoint-2xl: 96rem;
/* Animations */
--animate-fade-in: fade-in 0.3s ease-out;
--animate-slide-up: slide-up 0.4s ease-out;
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slide-up {
from { opacity: 0; transform: translateY(1rem); }
to { opacity: 1; transform: translateY(0); }
}
Theme variables become utilities automatically. --color-brand generates bg-brand, text-brand, border-brand, and other color utilities.
Choosing what to import
Import only what you need:
/* Full Tailwind (base + components + utilities) */
@import "tailwindcss";
/* Or import parts separately */
@import "tailwindcss/preflight"; /* CSS reset */
@import "tailwindcss/utilities"; /* Utility classes */
Preflight is Tailwind’s reset. It removes default margins, sets border-box sizing, normalizes form elements, and provides a consistent baseline.
Custom utilities with @utility
Define your own utilities using @utility:
@utility content-grid {
display: grid;
grid-template-columns: 1fr min(65ch, 100%) 1fr;
gap: var(--spacing-4);
& > * {
grid-column: 2;
}
}
@utility scrollbar-thin {
scrollbar-width: thin;
scrollbar-color: var(--color-gray-400) transparent;
}
Custom utilities work with Tailwind’s variants automatically. content-grid works. md:content-grid and hover:content-grid also work.
Layer organization
Tailwind v4 uses native CSS cascade layers:
@import "tailwindcss";
/* Your base styles */
@layer base {
body {
@apply antialiased text-gray-900 bg-white;
}
h1, h2, h3, h4 {
@apply font-semibold tracking-tight;
}
}
/* Your components */
@layer components {
.prose {
@apply max-w-none;
line-height: 1.75;
}
.prose p + p {
@apply mt-4;
}
}
/* Your utilities */
@layer utilities {
.text-balance {
text-wrap: balance;
}
}
The @apply directive lets you use Tailwind utilities inside custom CSS.
Modern color with OKLCH
Tailwind v4 supports modern color spaces:
@theme {
/* OKLCH for perceptually uniform colors */
--color-primary: oklch(55% 0.15 250);
--color-secondary: oklch(65% 0.1 150);
/* Semantic tokens */
--color-surface: oklch(98% 0.005 250);
--color-text: oklch(25% 0.02 250);
--color-text-muted: oklch(55% 0.05 250);
}
Using OKLCH means color variations match perceived lightness, not just RGB values. A lighter blue and lighter red will look equally light.
Container queries
Tailwind v4 includes container query variants:
<!-- Mark a container -->
<div class="@container">
<div class="@md:grid-cols-2 @lg:grid-cols-3 grid grid-cols-1 gap-4">
<!-- Responsive to container width, not viewport -->
</div>
</div>
@container enables container queries. @md: applies styles at a container width of 28rem. @lg: applies at 32rem.
Configure container sizes in your theme:
@theme {
--container-sm: 24rem;
--container-md: 28rem;
--container-lg: 32rem;
--container-xl: 36rem;
}
View transition support
Use Tailwind with native view transitions:
@layer utilities {
::view-transition-old(root) {
animation: fade-out 0.3s ease;
}
::view-transition-new(root) {
animation: fade-in 0.3s ease;
}
}
Tailwind’s animation utilities work alongside native view transition APIs.
Conditional variants
Configure variants for complex selectors:
@variant dark (&:where(.dark, .dark *));
@variant supports-container (&@container (width >= 400px));
@variant rtl (&:where([dir="rtl"], [dir="rtl"] *));
Custom variants allow targeting any CSS condition with Tailwind’s prefix syntax.
Integration with build tools
Tailwind v4 integrates directly with JavaScript build tools:
Vite (simplest setup):
// vite.config.js
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})
PostCSS:
// postcss.config.mjs
export default {
plugins: {
'@tailwindcss/postcss': {},
},
}
No additional configuration files needed. Tailwind reads your CSS and processes it.
Common project setup
A typical project structure:
src/
├── styles/
│ ├── main.css /* Tailwind entry + @theme */
│ ├── base.css /* Additional base styles */
│ ├── components.css /* Component patterns */
│ └── utilities.css /* Custom utilities */
└── main.js /* Imports ./styles/main.css */
/* main.css */
@import "tailwindcss";
/* Theme customization */
@theme {
--font-sans: "Inter", system-ui, sans-serif;
--color-brand: oklch(55% 0.15 250);
--color-surface: oklch(98% 0.005 250);
}
/* Base layer extensions */
@layer base {
html {
@apply antialiased;
}
:focus-visible {
@apply outline-2 outline-offset-2 outline-brand;
}
}
/* Component patterns */
@layer components {
.btn {
@apply inline-flex items-center justify-center rounded-md px-4 py-2 font-medium transition-colors;
}
.btn-primary {
@apply btn bg-brand text-white hover:bg-brand-dark;
}
.btn-secondary {
@apply btn border border-gray-300 bg-white text-gray-700 hover:bg-gray-50;
}
}
/* Utilities */
@layer utilities {
.text-balance {
text-wrap: balance;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
}
Migrating from custom CSS
Consider these steps when adopting Tailwind on an existing project:
- Install and configure Tailwind alongside existing CSS
- Replace utility-only styles first (margins, padding, flexbox)
- Extract component patterns with
@layer components - Gradually migrate complex custom CSS
- Remove unused custom CSS as you go
You do not need to migrate everything at once. Tailwind and custom CSS can coexist.
What to carry forward
- Tailwind v4 uses CSS-first configuration via
@themeinstead of JavaScript config - Theme variables use standard CSS custom property syntax
- Import
tailwindcssfor a complete setup, or import individual parts - Use
@layerfor base styles, components, and utilities - Use
@applyto compose utilities in custom CSS - Custom utilities defined with
@utilityautomatically support variants - Container queries, modern color spaces, and view transitions are fully supported
- Build tool integration is simpler with the v4 plugin architecture
When to use Tailwind v4
Tailwind v4 is a good choice when:
- You want modern CSS features with a utility-first approach
- You prefer configuration in CSS over JavaScript
- You are starting a new project or can migrate incrementally
- You want access to container queries, OKLCH colors, and native CSS nesting
Consider staying with custom CSS or other approaches when:
- You need full control over every style declaration
- Your project has strict CSS architecture requirements
- Your team prefers separation of markup and styling
- You are maintaining legacy codebases without build tool support