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.
Resources
3Install
npx skillscat add jezweb/claude-skills/tailwind-theme-builder Install via the SkillsCat registry.
We need to produce a 2-3 sentence plain-text summary, objective, factual, no marketing language, no superlatives, no calls to action, no bullet points, no headings, no markdown formatting. At most 60 words. Must not wrap answer in quotes. Just the summary text. We need to explain what the skill does, what problem it solves, when to use it. Skill: Set up Tailwind v4 with shadcn/ui themed UI. Workflow: install dependencies, configure CSS variables with @theme inline, set up dark mode, verify.
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
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.tsStep 2: Configure Vite
Copy assets/vite.config.ts or add the Tailwind plugin:
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:
@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:
import { ThemeProvider } from '@/components/theme-provider'
ReactDOM.createRoot(document.getElementById('root')!).render(
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
<App />
</ThemeProvider>
)Add a theme toggle:
pnpm dlx shadcn@latest add dropdown-menuSee references/dark-mode.md for the ModeToggle component.
Step 5: Configure components.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 inlineto map all CSS variables - Use
@tailwindcss/viteplugin (NOT PostCSS) - Delete
tailwind.config.tsif it exists
Never:
- Put
:root/.darkinside@layer base - Use
.dark { @theme { } }(v4 doesn't support nested @theme) - Double-wrap:
hsl(var(--background)) - Use
@applywith@layer baseclasses (use@utilityinstead)
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 <ThemeProvider> |
| 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 variablescomponents.json— shadcn/ui v4 configvite.config.ts— Vite + Tailwind plugintheme-provider.tsx— Dark mode providerutils.ts—cn()utility
Reference Files
references/common-gotchas.md— 8 documented errors with GitHub sourcesreferences/dark-mode.md— Complete dark mode implementationreferences/architecture.md— Deep dive into 4-step patternreferences/migration-guide.md— v3 to v4 migration