| name | tailwindcss |
| description | TailwindCSS v4 patterns — CSS-first @theme, design tokens, container queries, dark mode. Use when configuring Tailwind or defining tokens. |
| user-invocable | false |
TailwindCSS v4 Patterns
Overview
TailwindCSS v4 introduces a CSS-first approach, eliminating the need for JavaScript configuration files. All customization happens directly in CSS using new directives.
Key Changes from v3 to v4
| Feature | v3 | v4 |
|---|
| Configuration | tailwind.config.js | CSS @theme directive |
| Content detection | JS array | @source directive |
| Plugin loading | require() in JS | @plugin directive |
| Custom variants | JS API | @custom-variant directive |
| Custom utilities | JS API | @utility directive |
Browser Support
TailwindCSS v4 requires modern browsers:
- Safari 16.4+
- Chrome 111+
- Firefox 128+
Important: No CSS preprocessors (Sass/Less) needed - Tailwind IS the preprocessor.
Documentation Index
Core Documentation
Configuration Reference
CSS Features
Customization
CSS-First Configuration
Basic Setup
@import "tailwindcss";
This single import replaces the v3 directives (@tailwind base, @tailwind components, @tailwind utilities).
@theme Directive - Design Tokens
The @theme directive defines design tokens as CSS custom properties:
@import "tailwindcss";
@theme {
--color-primary: hsl(221 83% 53%);
--color-primary-dark: hsl(224 76% 48%);
--color-secondary: hsl(215 14% 34%);
--color-accent: hsl(328 85% 70%);
--color-success: oklch(0.723 0.191 142.5);
--color-warning: oklch(0.828 0.189 84.429);
--color-error: oklch(0.637 0.237 25.331);
--font-display: "Satoshi", "sans-serif";
--font-body: "Inter", "sans-serif";
--font-mono: "JetBrains Mono", "monospace";
--spacing-page: 2rem;
--spacing-section: 4rem;
: ;
: ;
: (, -, , );
: ;
: ;
}
Generated utilities from above:
- Colors:
bg-primary, text-primary-dark, border-accent
- Fonts:
font-display, font-body, font-mono
- Animations:
ease-spring, duration-fast
@theme inline Pattern
Use @theme inline to reference existing CSS variables without generating new utilities:
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--primary: oklch(0.205 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--primary: oklch(0.985 0 0);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-primary: var(--primary);
}
When to use @theme inline:
- Theming with CSS variables (light/dark mode)
- Shadcn/ui integration
- Dynamic theme switching
@source Directive - Content Detection
@import "tailwindcss";
@source "../node_modules/my-ui-library/src/**/*.{html,js}";
@source "../shared-components/**/*.tsx";
@source inline("bg-red-500 text-white p-4");
@custom-variant - Custom Variants
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@custom-variant rtl ([dir="rtl"] &);
@custom-variant print (@media print { & });
@custom-variant hover-desktop (@media (hover: hover) { &:hover });
@utility - Custom Utilities
@import "tailwindcss";
@utility text-balance {
text-wrap: balance;
}
@utility scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
&::-webkit-scrollbar {
display: none;
}
}
@utility flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@plugin - Plugin Configuration
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@plugin "@tailwindcss/container-queries";
@plugin "@tailwindcss/typography" {
className: prose;
}
@config - Legacy JS Configuration
When you need JS configuration (rare in v4):
@import "tailwindcss";
@config "./tailwind.config.ts";
Vite Integration
Installation
npm install tailwindcss @tailwindcss/vite
Vite Configuration
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import path from "path"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
})
CSS Entry Point
@import "tailwindcss";
@theme {
}
TypeScript Path Aliases
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
Modern CSS Features with Tailwind v4
Native CSS Variables
Tailwind v4 uses native CSS variables without wrapper functions:
--primary: 221 83% 53%;
background-color: hsl(var(--primary));
--color-primary: hsl(221 83% 53%);
oklch Color Format
@theme {
--color-brand: oklch(0.65 0.2 250);
--color-brand-light: oklch(0.85 0.15 250);
--color-brand-dark: oklch(0.45 0.25 250);
}
Benefits of oklch:
- Perceptually uniform
- Consistent lightness across hues
- Better for generating color scales
- Native browser support
Container Queries
<div class="@container">
<div class="grid grid-cols-1 @md:grid-cols-2 @lg:grid-cols-3">
</div>
</div>
.sidebar {
container-name: sidebar;
container-type: inline-size;
}
@container sidebar (min-width: 300px) {
.nav-item { }
}
:has() Pseudo-Class
<label class="group has-[:invalid]:border-red-500 has-[:focus]:ring-2">
<input type="email" class="peer" />
</label>
.card:has(> img) {
@apply p-0;
}
.form:has(:invalid) {
@apply border-red-500;
}
Native CSS Nesting
.card {
@apply rounded-lg bg-white shadow-md;
.header {
@apply border-b p-4;
}
.content {
@apply p-6;
}
&:hover {
@apply shadow-lg;
}
&.featured {
@apply border-2 border-primary;
}
}
Utility Patterns
Responsive Design (Mobile-First)
<div class="
p-4 text-sm /* Mobile */
sm:p-6 sm:text-base /* Tablet */
lg:p-8 lg:text-lg /* Desktop */
2xl:p-12 2xl:text-xl /* Large screens */
">
State Variants
<button class="
bg-primary text-white
hover:bg-primary-dark
focus:ring-2 focus:ring-primary focus:ring-offset-2
active:scale-95
disabled:opacity-50 disabled:cursor-not-allowed
">
<div class="group">
<span class="group-hover:underline">Label</span>
<span class="opacity-0 group-hover:opacity-100">Icon</span>
</div>
<input class="peer" />
<span class="invisible peer-focus:visible">Hint text</span>
Dark Mode
Strategy 1: Class-based (recommended)
@custom-variant dark (&:is(.dark *));
<html class="dark">
<body class="bg-white dark:bg-gray-900 text-black dark:text-white">
Strategy 2: Media query
@custom-variant dark (@media (prefers-color-scheme: dark) { & });
Animation Utilities
<div class="animate-spin" />
<div class="animate-pulse" />
<div class="animate-bounce" />
<div class="animate-[fadeIn_0.5s_ease-out]" />
@theme {
--animate-fade-in: fadeIn 0.5s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
Size Utility (v4)
<div class="w-10 h-10">
<div class="size-10">
Best Practices
When to Use @apply
Use @apply sparingly for true component abstraction:
@layer components {
.btn-primary {
@apply px-4 py-2 bg-primary text-white rounded-md;
@apply hover:bg-primary-dark focus:ring-2 focus:ring-primary;
@apply disabled:opacity-50 disabled:cursor-not-allowed;
@apply transition-colors duration-fast;
}
}
.my-special-div {
@apply mt-4 p-6 bg-gray-100;
}
Rule: Only extract patterns when reused 3+ times.
Design Token Naming
@theme {
--color-primary: hsl(221 83% 53%);
--color-primary-foreground: hsl(0 0% 100%);
--color-gray-50: oklch(0.985 0 0);
--color-gray-100: oklch(0.970 0 0);
--color-gray-900: oklch(0.145 0 0);
}
Performance
- Use Vite plugin - Automatic dead code elimination
- Avoid dynamic class names - Static analysis can't optimize them
- Purge unused styles - Automatic with proper @source config
<div class={isActive ? "bg-primary" : "bg-gray-100"}>
<div class={`bg-${color}-500`}>
CSS Layers Order
Tailwind v4 uses CSS cascade layers:
1. @layer base - Reset, typography defaults
2. @layer components - Reusable components
3. @layer utilities - Utility classes (highest priority)
Custom styles should go in appropriate layers:
@layer components {
.card { }
}
@layer utilities {
.text-shadow { }
}
Related Skills
- shadcn-ui - Component library using Tailwind (CSS variables, theming)
- css-modules - Alternative: scoped CSS for complex components
- react-typescript - React patterns with Tailwind className
- design-references - Design system guidelines (Tailwind UI reference)