Set up Tailwind v4 with shadcn/ui using @theme inline pattern and CSS variable architecture. Four-step pattern: CSS variables, Tailwind mapping, base styles, automatic dark mode. Prevents 8 documented errors. Use when initializing React projects with Tailwind v4, or fixing colors not working, tw-animate-css errors, @theme inline dark mode conflicts, @apply breaking, v3 migration issues.
Production-tested: WordPress Auditor (https://wordpress-auditor.webfonts.workers.dev)
Last Updated: 2026-01-20
Versions: [email protected], @tailwindcss/[email protected]
Status: Production Ready ✅
# 1) Install dependencies
pnpm add tailwindcss @tailwindcss/vite
pnpm add -D @types/node tw-animate-css
pnpm dlx shadcn@latest init
# 2) Remove v3 config if present
rm tailwind.config.ts
vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
import path from 'path'
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: { alias: { '@': path.resolve(__dirname, './src') } }
})
components.json (critical for v4)
{
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "slate",
"cssVariables": true
}
}
@import "tailwindcss";
@import "tw-animate-css";
:root {
--background: hsl(0 0% 100%);
--foreground: hsl(222.2 84% 4.9%);
--primary: hsl(221.2 83.2% 53.3%);
}
.dark {
--background: hsl(222.2 84% 4.9%);
--foreground: hsl(210 40% 98%);
--primary: hsl(217.2 91.2% 59.8%);
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
}
@layer base {
body {
background-color: var(--background);
color: var(--foreground);
}
}
<div className="bg-background text-foreground" />
ThemeProvider (template: templates/theme-provider.tsx)src/main.tsx.dark toggles on <html>pnpm dlx shadcn@latest add dropdown-menu):root and .dark at root level (not nested in @layer base)hsl(...)components.json tailwind config empty ("config": "")@tailwindcss/vite plugin for Vite projectstailwind.config.ts in v4 setups@theme (.dark { @theme { ... } })hsl(var(--background)))@apply with classes defined only in @layer base/components (v4 breaking change)@layer base order is safe without understanding native CSS layer precedence@theme inline vs @theme@theme inline for standard shadcn light/dark setups (default case) ✅@theme (without inline) for multi-theme/custom-variant systems (data-mode, theme palettes) ✅See references/troubleshooting.md (Error #6) for full rationale and examples.
@tailwindcss/vite installed and used in vite.config.tscomponents.json has "config": ""tailwind.config.ts removedsrc/index.css follows all 4 stepstemplates/index.css - complete CSS variables + mappingtemplates/components.json - shadcn v4 configtemplates/vite.config.ts - Vite plugin setuptemplates/theme-provider.tsx - ThemeProvidertemplates/utils.ts - cn() utilityreferences/setup-config.md - expanded setup/config patterns, plugin setup, file-by-file checksreferences/troubleshooting.md - full 8 documented errors and fixesreferences/v4-updates-and-plugins.md - OKLCH updates, built-ins, plugin syntax, migration gotchasreferences/architecture.md - deeper architecture explanationreferences/dark-mode.md - full ThemeProvider and toggle implementationreferences/migration-guide.md - hardcoded-color to semantic-token migration workflowreferences/common-gotchas.md - additional practical pitfallsSkill Version: 3.1.0
Tailwind v4: 4.1.18