---
name: tailwind-theme-builder
description: >
Set up Tailwind v4 with shadcn/ui themed UI. Workflow: install dependencies,
configure CSS variables with @theme inline, set up dark mode, verify.
Use when initialising React projects with Tailwind v4, setting up shadcn/ui theming,
or fixing colors not working, tw-animate-css errors, @theme inline dark mode conflicts,
@apply breaking, v3 migration issues.
---
# Tailwind Theme Builder
Set up a fully themed Tailwind v4 + shadcn/ui project with dark mode. Produces configured CSS, theme provider, and working component library.
## Workflow
### Step 1: Install Dependencies
```bash
pnpm add tailwindcss @tailwindcss/vite
pnpm add -D @types/node tw-animate-css
pnpm dlx shadcn@latest init
# Delete v3 config if it exists
rm -f tailwind.config.ts
```
### Step 2: Configure Vite
Copy `assets/vite.config.ts` or add the Tailwind plugin:
```typescript
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') } }
})
```
### Step 3: Four-Step CSS Architecture (Mandatory)
This exact order is required. Skipping steps breaks the theme.
**src/index.css:**
```css
@import "tailwindcss";
@import "tw-animate-css";
/* 1. Define CSS variables at root (NOT inside @layer base) */
:root {
--background: hsl(0 0% 100%);
--foreground: hsl(222.2 84% 4.9%);
--primary: hsl(221.2 83.2% 53.3%);
--primary-foreground: hsl(210 40% 98%);
/* ... all semantic tokens */
}
.dark {
--background: hsl(222.2 84% 4.9%);
--foreground: hsl(210 40% 98%);
--primary: hsl(217.2 91.2% 59.8%);
--primary-foreground: hsl(222.2 47.4% 11.2%);
}
/* 2. Map variables to Tailwind utilities */
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
}
/* 3. Apply base styles (NO hsl() wrapper here) */
@layer base {
body {
background-color: var(--background);
color: var(--foreground);
}
}
```
**Result:** `bg-background`, `text-primary` etc. work automatically. Dark mode switches via `.dark` class — no `dark:` variants needed for semantic colours.
### Step 4: Set Up Dark Mode
Copy `assets/theme-provider.tsx` to your components directory, then wrap your app:
```typescript
import { ThemeProvider } from '@/components/theme-provider'
ReactDOM.createRoot(document.getElementById('root')!).render(
)
```
Add a theme toggle:
```bash
pnpm dlx shadcn@latest add dropdown-menu
```
See `references/dark-mode.md` for the ModeToggle component.
### Step 5: Configure components.json
```json
{
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "slate",
"cssVariables": true
}
}
```
`"config": ""` is critical — v4 doesn't use tailwind.config.ts.
---
## Critical Rules
**Always:**
- Wrap colours with `hsl()` in `:root`/`.dark`
- Use `@theme inline` to map all CSS variables
- Use `@tailwindcss/vite` plugin (NOT PostCSS)
- Delete `tailwind.config.ts` if it exists
**Never:**
- Put `:root`/`.dark` inside `@layer base`
- Use `.dark { @theme { } }` (v4 doesn't support nested @theme)
- Double-wrap: `hsl(var(--background))`
- Use `@apply` with `@layer base` classes (use `@utility` instead)
---
## Common Errors
| Symptom | Cause | Fix |
|---------|-------|-----|
| `bg-primary` doesn't work | Missing `@theme inline` | Add `@theme inline` block |
| Colours all black/white | Double `hsl()` wrapping | Use `var(--colour)` not `hsl(var(--colour))` |
| Dark mode not switching | Missing ThemeProvider | Wrap app in `` |
| Build fails | `tailwind.config.ts` exists | Delete the file |
| Animation errors | Using `tailwindcss-animate` | Install `tw-animate-css` instead |
| `@apply` fails on custom class | v4 breaking change | Use `@utility` instead of `@layer components` |
See `references/common-gotchas.md` for detailed error explanations with sources.
---
## Asset Files
Copy from `assets/` directory:
- `index.css` — Complete CSS with all colour variables
- `components.json` — shadcn/ui v4 config
- `vite.config.ts` — Vite + Tailwind plugin
- `theme-provider.tsx` — Dark mode provider
- `utils.ts` — `cn()` utility
## Reference Files
- `references/common-gotchas.md` — 8 documented errors with GitHub sources
- `references/dark-mode.md` — Complete dark mode implementation
- `references/architecture.md` — Deep dive into 4-step pattern
- `references/migration-guide.md` — v3 to v4 migration