tailwind-v4-shadcn
π―Skillfrom ovachiever/droid-tings
Configures Tailwind v4 with shadcn/ui, automating CSS variable setup, dark mode, and preventing common initialization errors.
Part of
ovachiever/droid-tings(370 items)
Installation
git clone https://github.com/ovachiever/droid-tings.gitSkill Details
|
Overview
# Tailwind v4 + shadcn/ui Production Stack
Production-tested: WordPress Auditor (https://wordpress-auditor.webfonts.workers.dev)
Last Updated: 2025-11-09
Status: Production Ready β
---
β οΈ BEFORE YOU START (READ THIS!)
CRITICAL FOR AI AGENTS: If you're Claude Code helping a user set up Tailwind v4:
- Explicitly state you're using this skill at the start of the conversation
- Reference patterns from the skill rather than general knowledge
- Prevent known issues listed in
reference/common-gotchas.md - Don't guess - if unsure, check the skill documentation
USER ACTION REQUIRED: Tell Claude to check this skill first!
Say: "I'm setting up Tailwind v4 + shadcn/ui - check the tailwind-v4-shadcn skill first"
Why This Matters (Real-World Results)
Without skill activation:
- β Setup time: ~5 minutes
- β Errors encountered: 2-3 (tw-animate-css, duplicate @layer base)
- β Manual fixes needed: 2+ commits
- β Token usage: ~65k
- β User confidence: Required debugging
With skill activation:
- β Setup time: ~1 minute
- β Errors encountered: 0
- β Manual fixes needed: 0
- β Token usage: ~20k (70% reduction)
- β User confidence: Instant success
Known Issues This Skill Prevents
- tw-animate-css import error (deprecated in v4)
- Duplicate @layer base blocks (shadcn init adds its own)
- Wrong template selection (vanilla TS vs React)
- Missing post-init cleanup (incompatible CSS rules)
- Wrong plugin syntax (using @import or require() instead of @plugin directive)
All of these are handled automatically when the skill is active.
---
Quick Start (5 Minutes - Follow This Exact Order)
1. Install Dependencies
```bash
pnpm add tailwindcss @tailwindcss/vite
pnpm add -D @types/node
pnpm dlx shadcn@latest init
```
2. Configure Vite
```typescript
// 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')
}
}
})
```
3. Update components.json
```json
{
"tailwind": {
"config": "", // β CRITICAL: Empty for v4
"css": "src/index.css",
"baseColor": "slate", // Base color palette
"cssVariables": true,
"prefix": "" // No prefix for utility classes
}
}
```
4. Delete tailwind.config.ts
```bash
rm tailwind.config.ts # v4 doesn't use this file
```
---
The Four-Step Architecture (CRITICAL)
This pattern is mandatory - skipping steps will break your theme.
Step 1: Define CSS Variables at Root Level
```css
/ src/index.css /
@import "tailwindcss";
:root {
--background: hsl(0 0% 100%); / β hsl() wrapper required /
--foreground: hsl(222.2 84% 4.9%);
--primary: hsl(221.2 83.2% 53.3%);
/ ... all light mode colors /
}
.dark {
--background: hsl(222.2 84% 4.9%);
--foreground: hsl(210 40% 98%);
--primary: hsl(217.2 91.2% 59.8%);
/ ... all dark mode colors /
}
```
Critical Rules:
- β
Define at root level (NOT inside
@layer base) - β
Use
hsl()wrapper on all color values - β
Use
.darkfor dark mode (NOT.dark { @theme { } })
Step 2: Map Variables to Tailwind Utilities
```css
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
/ ... map ALL CSS variables /
}
```
Why This Is Required:
- Generates utility classes (
bg-background,text-primary) - Without this,
bg-primaryetc. won't exist
Step 3: Apply Base Styles
```css
@layer base {
body {
background-color: var(--background); / NO hsl() here /
color: var(--foreground);
}
}
```
Critical Rules:
- β
Reference variables directly:
var(--background) - β Never double-wrap:
hsl(var(--background))
Step 4: Result - Automatic Dark Mode
```tsx
{/ No dark: variants needed - theme switches automatically /}
```
---
Dark Mode Setup
1. Create ThemeProvider
See reference/dark-mode.md for full implementation or use template:
```typescript
// Copy from: templates/theme-provider.tsx
```
2. Wrap Your App
```typescript
// src/main.tsx
import { ThemeProvider } from '@/components/theme-provider'
ReactDOM.createRoot(document.getElementById('root')!).render(
,
)
```
3. Add Theme Toggle
```bash
pnpm dlx shadcn@latest add dropdown-menu
```
See reference/dark-mode.md for ModeToggle component code.
---
Critical Rules (MUST FOLLOW)
β Always Do:
- Wrap color values with
hsl()in:rootand.dark
```css
--background: hsl(0 0% 100%); / β Correct /
```
- Use
@theme inlineto map all CSS variables
```css
@theme inline {
--color-background: var(--background);
}
```
- Set
"tailwind.config": ""in components.json
```json
{ "tailwind": { "config": "" } }
```
- Delete
tailwind.config.tsif it exists
- Use
@tailwindcss/viteplugin (NOT PostCSS)
- Use
cn()for conditional classes
```typescript
import { cn } from "@/lib/utils"
```
β Never Do:
- Put
:rootor.darkinside@layer base
```css
/ WRONG /
@layer base {
:root { --background: hsl(...); }
}
```
- Use
.dark { @theme { } }pattern
```css
/ WRONG - v4 doesn't support nested @theme /
.dark {
@theme {
--color-primary: hsl(...);
}
}
```
- Double-wrap colors
```css
/ WRONG /
body {
background-color: hsl(var(--background));
}
```
- Use
tailwind.config.tsfor theme colors
```typescript
/ WRONG - v4 ignores this /
export default {
theme: {
extend: {
colors: { primary: 'hsl(var(--primary))' }
}
}
}
```
- Use
@applydirective (deprecated in v4)
- Use
dark:variants for semantic colors
```tsx
/ WRONG /
/ CORRECT /
```
---
Semantic Color Tokens
Always use semantic names for colors:
```css
:root {
--destructive: hsl(0 84.2% 60.2%); / Red - errors, critical /
--success: hsl(142.1 76.2% 36.3%); / Green - success states /
--warning: hsl(38 92% 50%); / Yellow - warnings /
--info: hsl(221.2 83.2% 53.3%); / Blue - info, primary /
}
```
Usage:
```tsx
```
---
Common Issues & Quick Fixes
| Symptom | Cause | Fix |
|---------|-------|-----|
| bg-primary doesn't work | Missing @theme inline mapping | Add @theme inline block |
| Colors all black/white | Double hsl() wrapping | Use var(--color) not hsl(var(--color)) |
| Dark mode not switching | Missing ThemeProvider | Wrap app in |
| Build fails | tailwind.config.ts exists | Delete the file |
| Text invisible | Wrong contrast colors | Check color definitions in :root/.dark |
See reference/common-gotchas.md for complete troubleshooting guide.
---
File Templates
All templates are available in the templates/ directory:
- index.css - Complete CSS setup with all color variables
- components.json - shadcn/ui v4 configuration
- vite.config.ts - Vite + Tailwind plugin setup
- tsconfig.app.json - TypeScript with path aliases
- theme-provider.tsx - Dark mode provider with localStorage
- utils.ts -
cn()utility for class merging
Copy these files to your project and customize as needed.
---
Complete Setup Checklist
- [ ] Vite + React + TypeScript project created
- [ ]
@tailwindcss/viteinstalled (NOT postcss) - [ ]
vite.config.tsusestailwindcss()plugin - [ ]
tsconfig.jsonhas path aliases configured - [ ]
components.jsonexists with"config": "" - [ ] NO
tailwind.config.tsfile exists - [ ]
src/index.cssfollows v4 pattern:
- [ ] :root and .dark at root level (not in @layer)
- [ ] Colors wrapped with hsl()
- [ ] @theme inline maps all variables
- [ ] @layer base uses unwrapped variables
- [ ] Theme provider installed and wrapping app
- [ ] Dark mode toggle component created
- [ ] Test theme switching works in browser
---
Advanced Topics
Custom Colors
Add new semantic colors:
```css
:root {
--brand: hsl(280 65% 60%);
--brand-foreground: hsl(0 0% 100%);
}
.dark {
--brand: hsl(280 75% 70%);
--brand-foreground: hsl(280 20% 10%);
}
@theme inline {
--color-brand: var(--brand);
--color-brand-foreground: var(--brand-foreground);
}
```
Usage:
Migration from v3
See reference/migration-guide.md for complete v3 β v4 migration steps.
Component Best Practices
- Always use semantic tokens
```tsx
/ β /
/ β /
```
- Use
cn()for conditional styling
```tsx
import { cn } from "@/lib/utils"
"base-class", isActive && "active-class", hasError && "error-class" )} /> ``` ```tsx ``` ---
Dependencies
β Install These
```json
{
"dependencies": {
"tailwindcss": "^4.1.17",
"@tailwindcss/vite": "^4.1.17",
"clsx": "^2.1.1",
"tailwind-merge": "^3.3.1",
"@radix-ui/react-*": "latest",
"lucide-react": "^0.553.0",
"react": "^19.2.0",
"react-dom": "^19.2.0"
},
"devDependencies": {
"@types/node": "^24.10.0",
"@vitejs/plugin-react": "^5.1.0",
"vite": "^7.2.2",
"typescript": "~5.9.0",
"tw-animate-css": "^1.4.0"
}
}
```
Animation Packages (Updated Nov 2025)
shadcn/ui has deprecated tailwindcss-animate in favor of tw-animate-css for Tailwind v4 compatibility.
β DO Install (v4-compatible):
```bash
pnpm add -D tw-animate-css
```
Then add to src/index.css:
```css
@import "tailwindcss";
@import "tw-animate-css";
```
β DO NOT Install:
```bash
npm install tailwindcss-animate # Deprecated - v3 only
```
Why: tw-animate-css is the official v4-compatible replacement for animations, required by shadcn/ui components.
Reference: https://ui.shadcn.com/docs/tailwind-v4
---
Tailwind v4 Plugins
Tailwind v4 supports official plugins using the @plugin directive in CSS.
Official Plugins (Tailwind Labs)
#### Typography Plugin - Style Markdown/CMS Content
When to use: Displaying blog posts, documentation, or any HTML from Markdown/CMS.
Installation:
```bash
pnpm add -D @tailwindcss/typography
```
Configuration (v4 syntax):
```css
/ src/index.css /
@import "tailwindcss";
@plugin "@tailwindcss/typography";
```
Usage:
```html
{{ markdown_content }}
```
Available classes:
prose- Base typography stylesprose-sm,prose-base,prose-lg,prose-xl,prose-2xl- Size variantsdark:prose-invert- Dark mode styles
---
#### Forms Plugin - Reset Form Element Styles
When to use: Building custom forms without shadcn/ui components, or need consistent cross-browser form styling.
Installation:
```bash
pnpm add -D @tailwindcss/forms
```
Configuration (v4 syntax):
```css
/ src/index.css /
@import "tailwindcss";
@plugin "@tailwindcss/forms";
```
What it does:
- Resets browser default form styles
- Makes form elements styleable with Tailwind utilities
- Fixes cross-browser inconsistencies for inputs, selects, checkboxes, radios
Note: Less critical for shadcn/ui users (they have pre-styled form components), but still useful for basic forms.
---
Common Plugin Errors
These errors happen when using v3 syntax in v4 projects:
β WRONG (v3 config file syntax):
```js
// tailwind.config.js
module.exports = {
plugins: [require('@tailwindcss/typography')]
}
```
β WRONG (@import instead of @plugin):
```css
@import "@tailwindcss/typography"; / Doesn't work /
```
β CORRECT (v4 @plugin directive):
```css
/ src/index.css /
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
```
---
Built-in Features (No Plugin Needed)
Container queries are built into Tailwind v4 core - no plugin needed:
```tsx
Responds to container width, not viewport
```
β Don't install: @tailwindcss/container-queries (deprecated, now core feature)
---
Reference Documentation
For deeper understanding, see:
- architecture.md - Deep dive into the 4-step pattern
- dark-mode.md - Complete dark mode implementation
- common-gotchas.md - All the ways it can break (and fixes)
- migration-guide.md - Migrating hardcoded colors to CSS variables
---
Official Documentation
- shadcn/ui Vite Setup: https://ui.shadcn.com/docs/installation/vite
- shadcn/ui Tailwind v4 Guide: https://ui.shadcn.com/docs/tailwind-v4
- shadcn/ui Dark Mode (Vite): https://ui.shadcn.com/docs/dark-mode/vite
- Tailwind v4 Docs: https://tailwindcss.com/docs
- shadcn/ui Theming: https://ui.shadcn.com/docs/theming
---
Production Example
This skill is based on the WordPress Auditor project:
- Live: https://wordpress-auditor.webfonts.workers.dev
- Stack: Vite + React 19 + Tailwind v4 + shadcn/ui + Cloudflare Workers
- Dark Mode: Full system/light/dark support
- Version: Tailwind v4.1.14 + shadcn/ui latest (Oct 2025)
All patterns in this skill have been validated in production.
---
Questions? Issues?
- Check
reference/common-gotchas.mdfirst - Verify all steps in the 4-step architecture
- Ensure
components.jsonhas"config": "" - Delete
tailwind.config.tsif it exists - Check official docs: https://ui.shadcn.com/docs/tailwind-v4
More from this repository10
nextjs-shadcn-builder skill from ovachiever/droid-tings
security-auditor skill from ovachiever/droid-tings
threejs-graphics-optimizer skill from ovachiever/droid-tings
api-documenter skill from ovachiever/droid-tings
secret-scanner skill from ovachiever/droid-tings
readme-updater skill from ovachiever/droid-tings
applying-brand-guidelines skill from ovachiever/droid-tings
deep-reading-analyst skill from ovachiever/droid-tings
dependency-auditor skill from ovachiever/droid-tings
Validates and type-checks React forms using React Hook Form and Zod, ensuring seamless client-side and server-side validation with TypeScript type inference.