Tailwind CSS v4 Best Practices Quick Reference
Vite Plugin Setup:
// vite.config.ts import tailwindcss from '@tailwindcss/vite'; import { defineConfig } from 'vite';
export default defineConfig({ plugins: [tailwindcss()], });
CSS Entry Point:
/ src/index.css / @import 'tailwindcss';
@theme Inline Directive:
@theme inline { --color-primary: oklch(60% 0.24 262); --color-surface: oklch(98% 0.002 247); }
Key Differences from v3 Feature v3 v4 Configuration tailwind.config.js @theme in CSS Build Tool PostCSS plugin @tailwindcss/vite Colors rgb() / hsl() oklch() (default) Theme Extension extend: {} in JS CSS variables Dark Mode darkMode config option CSS variants @theme Directive Modes default (standard mode)
Generates CSS variables that can be referenced elsewhere:
@theme { --color-brand: oklch(60% 0.24 262); }
/ Generates: :root { --color-brand: oklch(...); } / / Usage: text-brand → color: var(--color-brand) /
Note: You can also use @theme default explicitly to mark theme values that can be overridden by non-default @theme declarations.
inline
Inlines values directly without CSS variables (better performance):
@theme inline { --color-brand: oklch(60% 0.24 262); }
/ Usage: text-brand → color: oklch(60% 0.24 262) /
reference
Inlines values as fallbacks without emitting CSS variables:
@theme reference { --color-internal: oklch(50% 0.1 180); }
/ No :root variable, but utilities use fallback / / Usage: bg-internal → background-color: var(--color-internal, oklch(50% 0.1 180)) /
OKLCH Color Format
OKLCH provides perceptually uniform colors with better consistency across hues:
oklch(L% C H)
L (Lightness): 0% (black) to 100% (white) C (Chroma): 0 (gray) to ~0.4 (vibrant) H (Hue): 0-360 degrees (red → yellow → green → blue → magenta)
Examples:
--color-sky-500: oklch(68.5% 0.169 237.323); / Bright blue / --color-red-600: oklch(57.7% 0.245 27.325); / Vibrant red / --color-zinc-900: oklch(21% 0.006 285.885); / Near-black gray /
CSS Variable Naming
Tailwind v4 uses double-dash CSS variable naming conventions:
@theme { / Colors: --color-{name}-{shade} / --color-primary-500: oklch(60% 0.24 262);
/ Spacing: --spacing multiplier / --spacing: 0.25rem; / Base unit for spacing scale /
/ Fonts: --font-{family} / --font-display: 'Inter Variable', system-ui, sans-serif;
/ Breakpoints: --breakpoint-{size} / --breakpoint-lg: 64rem;
/ Custom animations: --animate-{name} / --animate-fade-in: fade-in 0.3s ease-out; }
No Config Files Needed
Tailwind v4 eliminates configuration files:
No tailwind.config.js - Use @theme in CSS instead No postcss.config.js - Use @tailwindcss/vite plugin TypeScript support - Add @types/node for path resolution { "devDependencies": { "@tailwindcss/vite": "^4.0.0", "@types/node": "^22.0.0", "tailwindcss": "^4.0.0", "vite": "^6.0.0" } }
Progressive Disclosure Setup & Installation: See references/setup.md for Vite plugin configuration, package setup, TypeScript config Theming & Design Tokens: See references/theming.md for @theme modes, color palettes, custom fonts, animations Dark Mode Strategies: See references/dark-mode.md for media queries, class-based, attribute-based approaches Decision Guide When to use @theme inline vs default
Use @theme inline:
Better performance (no CSS variable overhead) Static color values that won't change Animation keyframes with multiple values Utilities that need direct value inlining
Use @theme (default):
Dynamic theming with JavaScript CSS variable references in custom CSS Values that change based on context Better debugging (inspect CSS variables in DevTools) When to use @theme reference
Use @theme reference:
Provide fallback values without CSS variable overhead Values that should work even if variable isn't defined Reducing :root bloat while maintaining utility support Combining with inline for direct value substitution Common Patterns Two-Tier Variable System
Semantic variables that map to design tokens:
@theme { / Design tokens (OKLCH colors) / --color-blue-600: oklch(54.6% 0.245 262.881); --color-slate-800: oklch(27.9% 0.041 260.031);
/ Semantic mappings / --color-primary: var(--color-blue-600); --color-surface: var(--color-slate-800); }
/ Usage: bg-primary, bg-surface /
Custom Font Configuration @theme { --font-display: 'Inter Variable', system-ui, sans-serif; --font-mono: 'JetBrains Mono', ui-monospace, monospace;
--font-display--font-variation-settings: 'wght' 400; --font-display--font-feature-settings: 'cv02', 'cv03', 'cv04'; }
/ Usage: font-display, font-mono /
Animation Keyframes @theme inline { --animate-beacon: beacon 2s ease-in-out infinite;
@keyframes beacon { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(1.05); } } }
/ Usage: animate-beacon /