tailwind-v4-shadcn

安装量: 36
排名: #19410

安装

npx skills add https://github.com/jezweb/claude-skills --skill tailwind-v4-shadcn
Tailwind v4 + shadcn/ui Production Stack
Production-tested
WordPress Auditor (
https://wordpress-auditor.webfonts.workers.dev
)
Last Updated
2026-01-20
Versions
tailwindcss@4.1.18, @tailwindcss/vite@4.1.18
Status
Production Ready ✅ Quick Start (Follow This Exact Order)

1. Install dependencies

pnpm add tailwindcss @tailwindcss/vite pnpm add -D @types/node tw-animate-css pnpm dlx shadcn@latest init

2. Delete v3 config if exists

rm tailwind.config.ts

v4 doesn't use this file

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):
{
"tailwind"
:
{
"config"
:
""
,
// ← Empty for v4
"css"
:
"src/index.css"
,
"baseColor"
:
"slate"
,
"cssVariables"
:
true
}
}
The Four-Step Architecture (MANDATORY)
Skipping steps will break your theme. Follow exactly:
Step 1: Define CSS Variables at Root
/ src/index.css /
@import
"tailwindcss"
;
@import
"tw-animate-css"
;
/ Required for shadcn/ui animations /
: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
Define at root level (NOT inside
@layer base
). Use
hsl()
wrapper.
Step 2: Map Variables to Tailwind Utilities
@theme
inline
{
--color-background
:
var
(
--background
)
;
--color-foreground
:
var
(
--foreground
)
;
--color-primary
:
var
(
--primary
)
;
/ ... map ALL CSS variables /
}
Why
Generates utility classes (
bg-background
,
text-primary
). Without this, utilities won't exist.
Step 3: Apply Base Styles
@layer
base
{
body
{
background-color
:
var
(
--background
)
;
/ NO hsl() wrapper here /
color
:
var
(
--foreground
)
;
}
}
Critical
Reference variables directly. Never double-wrap:
hsl(var(--background))
.
Step 4: Result - Automatic Dark Mode
<
div
className
=
"
bg-background text-foreground
"
>
{
/ No dark: variants needed - theme switches automatically /
}
</
div
>
Dark Mode Setup
1. Create ThemeProvider
(see
templates/theme-provider.tsx
)
2. Wrap App
:
// src/main.tsx
import
{
ThemeProvider
}
from
'@/components/theme-provider'
ReactDOM
.
createRoot
(
document
.
getElementById
(
'root'
)
!
)
.
render
(
<
ThemeProvider defaultTheme
=
"dark"
storageKey
=
"vite-ui-theme"
>
<
App
/
>
<
/
ThemeProvider
>
)
3. Add Theme Toggle
:
pnpm
dlx shadcn@latest
add
dropdown-menu
See
reference/dark-mode.md
for ModeToggle component.
Critical Rules
✅ Always Do:
Wrap colors with
hsl()
in
:root
/
.dark
:
--bg: hsl(0 0% 100%);
Use
@theme inline
to map all CSS variables
Set
"tailwind.config": ""
in components.json
Delete
tailwind.config.ts
if exists
Use
@tailwindcss/vite
plugin (NOT PostCSS)
❌ Never Do:
Put
:root
/
.dark
inside
@layer base
(causes cascade issues)
Use
.dark { @theme { } }
pattern (v4 doesn't support nested @theme)
Double-wrap colors:
hsl(var(--background))
Use
tailwind.config.ts
for theme (v4 ignores it)
Use
@apply
directive (deprecated in v4, see error #7)
Use
dark:
variants for semantic colors (auto-handled)
Use
@apply
with
@layer base
or
@layer components
classes (v4 breaking change - use
@utility
instead) |
Source
Wrap ANY styles in
@layer base
without understanding CSS layer ordering (see error #8) |
Source
Common Errors & Solutions
This skill prevents
8 documented errors
.
1. ❌ tw-animate-css Import Error
Error
"Cannot find module 'tailwindcss-animate'"
Cause
shadcn/ui deprecated tailwindcss-animate for v4. Solution :

✅ DO

pnpm add -D tw-animate-css

Add to src/index.css:

@import "tailwindcss" ; @import "tw-animate-css" ;

❌ DON'T

npm install tailwindcss-animate

v3 only

  1. ❌ Colors Not Working
    Error
    :
    bg-primary
    doesn't apply styles
    Cause
    Missing @theme inline mapping Solution : @theme inline { --color-background : var ( --background ) ; --color-foreground : var ( --foreground ) ; --color-primary : var ( --primary ) ; / ... map ALL CSS variables / }
  2. ❌ Dark Mode Not Switching
    Error
    Theme stays light/dark
    Cause
    Missing ThemeProvider Solution : Create ThemeProvider (see templates/theme-provider.tsx ) Wrap app in main.tsx Verify .dark class toggles on
element 4. ❌ Duplicate @layer base Error : "Duplicate @layer base" in console Cause : shadcn init adds @layer base - don't add another Solution : /* ✅ Correct - single @layer base */ @import "tailwindcss" ; :root { --background : hsl ( 0 0 % 100 % ) ; } @theme inline { --color-background : var ( --background ) ; } @layer base { body { background-color : var ( --background ) ; } } 5. ❌ Build Fails with tailwind.config.ts Error : "Unexpected config file" Cause : v4 doesn't use tailwind.config.ts (v3 legacy) Solution : rm tailwind.config.ts v4 configuration happens in src/index.css using @theme directive. 6. ❌ @theme inline Breaks Dark Mode in Multi-Theme Setups Error : Dark mode doesn't switch when using @theme inline with custom variants (e.g., data-mode="dark" ) Source : GitHub Discussion #18560 Cause : @theme inline bakes variable VALUES into utilities at build time. When dark mode changes the underlying CSS variables, utilities don't update because they reference hardcoded values, not variables. Why It Happens : @theme inline inlines VALUES at build time: bg-primary → background-color: oklch(...) Dark mode overrides change the CSS variables, but utilities already have baked-in values The CSS specificity chain breaks Solution : Use @theme (without inline) for multi-theme scenarios: /* ✅ CORRECT - Use @theme without inline */ @custom-variant dark ( & : where ( [data-mode=dark] , [data-mode=dark] * ) ) ; @theme { --color-text-primary : var ( --color-slate-900 ) ; --color-bg-primary : var ( --color-white ) ; } @layer theme { [ data-mode = "dark" ] { --color-text-primary : var ( --color-white ) ; --color-bg-primary : var ( --color-slate-900 ) ; } } When to use inline : Single theme + dark mode toggle (like shadcn/ui default) ✅ Referencing other CSS variables that don't change ✅ When NOT to use inline : Multi-theme systems (data-theme="blue" | "green" | etc.) ❌ Dynamic theme switching beyond light/dark ❌ Maintainer Guidance (Adam Wathan): "It's more idiomatic in v4 for the actual generated CSS to reference your theme variables. I would personally only use inline when things don't work without it." 7. ❌ @apply with @layer base/components (v4 Breaking Change) Error : Cannot apply unknown utility class: custom-button Source : GitHub Discussion #17082 Cause : In v3, classes defined in @layer base and @layer components could be used with @apply . In v4, this is a breaking architectural change. Why It Happens : v4 doesn't "hijack" the native CSS @layer at-rule anymore. Only classes defined with @utility are available to @apply . Migration : /* ❌ v3 pattern (worked) */ @layer components { .custom-button { @apply px-4 py-2 bg-blue-500 ; } } /* ✅ v4 pattern (required) */ @utility custom-button { @apply px-4 py-2 bg-blue-500 ; } /* OR use native CSS */ @layer base { .custom-button { padding : 1 rem 0.5 rem ; background-color : theme ( colors. blue .500 ) ; } } Note : This skill already discourages @apply usage. This error is primarily for users migrating from v3. 8. ❌ @layer base Styles Not Applying Error : Styles defined in @layer base seem to be ignored Source : GitHub Discussion #16002 | Discussion #18123 Cause : v4 uses native CSS layers. Base styles CAN be overridden by utility layers due to CSS cascade if layers aren't explicitly ordered. Why It Happens : v3: Tailwind intercepted @layer base/components/utilities and processed them specially v4: Uses native CSS layers - if you don't import layers in the right order, precedence breaks Styles ARE being applied, but utilities override them Solution Option 1 : Define layers explicitly: @import "tailwindcss/theme.css" layer ( theme ) ; @import "tailwindcss/base.css" layer ( base ) ; @import "tailwindcss/components.css" layer ( components ) ; @import "tailwindcss/utilities.css" layer ( utilities ) ; @layer base { body { background-color : var ( --background ) ; } } Solution Option 2 (Recommended): Don't use @layer base - define styles at root level: @import "tailwindcss" ; :root { --background : hsl ( 0 0 % 100 % ) ; } body { background-color : var ( --background ) ; /* No @layer needed */ } Applies to : ALL base styles, not just color variables. Avoid wrapping ANY styles in @layer base unless you understand CSS layer ordering. Quick Reference Symptom Cause Fix bg-primary doesn't work Missing @theme inline 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 file Animation errors Using tailwindcss-animate Install tw-animate-css What's New in Tailwind v4 OKLCH Color Space (December 2024) Tailwind v4.0 replaced the entire default color palette with OKLCH, a perceptually uniform color space. Source : Tailwind v4.0 Release | OKLCH Migration Guide Why OKLCH : Perceptual consistency : HSL's "50% lightness" is visually inconsistent across hues (yellow appears much brighter than blue at same lightness) Better gradients : Smooth transitions without muddy middle colors Wider gamut : Supports colors beyond sRGB on modern displays More vibrant colors : Eye-catching, saturated colors previously limited by sRGB Browser Support (January 2026): Chrome 111+, Firefox 113+, Safari 15.4+, Edge 111+ Global coverage: 93.1% Automatic Fallbacks : Tailwind generates sRGB fallbacks for older browsers: .bg-blue-500 { background-color : #3b82f6 ; /* sRGB fallback */ background-color : oklch ( 0.6 0.24 264 ) ; /* Modern browsers */ } Custom Colors : When defining custom colors, OKLCH is now preferred: @theme { /* Modern approach (preferred) */ --color-brand : oklch ( 0.7 0.15 250 ) ; /* Legacy approach (still works) */ --color-brand : hsl ( 240 80 % 60 % ) ; } Migration : No breaking changes - Tailwind generates fallbacks automatically. For new projects, use OKLCH-aware tooling for custom colors. Built-in Features (No Plugin Needed) Container Queries (built-in as of v4.0): < div className = " @container " > < div className = " @md:text-lg @lg:grid-cols-2 " > Content responds to container width, not viewport Line Clamp (built-in as of v3.3): < p className = " line-clamp-3 " > Truncate to 3 lines with ellipsis... < p className = " line-clamp-[8] " > Arbitrary values supported < p className = " line-clamp-(--teaser-lines) " > CSS variable support Removed Plugins : @tailwindcss/container-queries - Built-in now @tailwindcss/line-clamp - Built-in since v3.3 Tailwind v4 Plugins Use @plugin directive (NOT require() or @import ): Typography (for Markdown/CMS content): pnpm add -D @tailwindcss/typography @import "tailwindcss" ; @plugin "@tailwindcss/typography" ; < article class = " prose dark:prose-invert " > {{ content }} Forms (cross-browser form styling): pnpm add -D @tailwindcss/forms @import "tailwindcss" ; @plugin "@tailwindcss/forms" ; Container Queries (built-in, no plugin needed): < div className = " @container " > < div className = " @md:text-lg " > Responds to container width Common Plugin Errors : /* ❌ WRONG - v3 syntax */ @import "@tailwindcss/typography" ; /* ✅ CORRECT - v4 syntax */ @plugin "@tailwindcss/typography" ; Setup Checklist @tailwindcss/vite installed (NOT postcss) vite.config.ts uses tailwindcss() plugin components.json has "config": "" NO tailwind.config.ts exists src/index.css follows 4-step pattern: :root / .dark at root level (not in @layer) Colors wrapped with hsl() @theme inline maps all variables @layer base uses unwrapped variables ThemeProvider wraps app Theme toggle works File Templates Available in templates/ directory: index.css - Complete CSS with all color variables components.json - shadcn/ui v4 config vite.config.ts - Vite + Tailwind plugin theme-provider.tsx - Dark mode provider utils.ts - cn() utility Migration from v3 See reference/migration-guide.md for complete guide. Key Changes : Delete tailwind.config.ts Move theme to CSS with @theme inline Replace @tailwindcss/line-clamp (now built-in: line-clamp-* ) Replace tailwindcss-animate with tw-animate-css Update plugins: require() → @plugin Additional Migration Gotchas Automated Migration Tool May Fail Warning : The @tailwindcss/upgrade utility often fails to migrate configurations. Source : Community Reports | GitHub Discussion #16642 Common failures : Typography plugin configurations Complex theme extensions Custom plugin setups Recommendation : Don't rely on automated migration. Follow manual steps in the migration guide instead. Default Element Styles Removed Tailwind v4 takes a more minimal approach to Preflight, removing default styles for headings, lists, and buttons. Source : GitHub Discussion #16517 | Medium: Migration Problems Impact : All headings (

through

) render at same size Lists lose default padding Visual regressions in existing projects Solutions : Option 1: Use @tailwindcss/typography for content pages : pnpm add -D @tailwindcss/typography @import "tailwindcss" ; @plugin "@tailwindcss/typography" ; < article className = " prose dark:prose-invert " > { /* All elements styled automatically */ } Option 2: Add custom base styles : @layer base { h1 { @apply text-4 xl font-bold mb-4 ; } h2 { @apply text-3 xl font-bold mb-3 ; } h3 { @apply text-2 xl font-bold mb-2 ; } ul { @apply list-disc pl-6 mb-4 ; } ol { @apply list-decimal pl-6 mb-4 ; } } PostCSS Setup Complexity Recommendation : Use @tailwindcss/vite plugin for Vite projects instead of PostCSS. Source : Medium: Migration Problems | GitHub Discussion #15764 Why Vite Plugin is Better : // ✅ Vite Plugin - One line, no PostCSS config import tailwindcss from '@tailwindcss/vite' export default defineConfig ( { plugins : [ react ( ) , tailwindcss ( ) ] , } ) // ❌ PostCSS - Multiple steps, plugin compatibility issues // 1. Install @tailwindcss/postcss // 2. Configure postcss.config.js // 3. Manage plugin order // 4. Debug plugin conflicts PostCSS Problems Reported : Error: "It looks like you're trying to use tailwindcss directly as a PostCSS plugin" Multiple PostCSS plugins required: postcss-import , postcss-advanced-variables , tailwindcss/nesting v4 PostCSS plugin is separate package: @tailwindcss/postcss Official Guidance : The Vite plugin is recommended for Vite projects. PostCSS is for legacy setups or non-Vite environments. Visual Changes Ring Width Default : Changed from 3px to 1px Source : Medium: Migration Guide ring class is now thinner Use ring-3 to match v3 appearance // v3: 3px ring < button className = " ring " > Button // v4: 1px ring (thinner) < button className = " ring " > Button // Match v3 appearance < button className = " ring-3 " > Button Reference Documentation architecture.md - Deep dive into 4-step pattern dark-mode.md - Complete dark mode implementation common-gotchas.md - Troubleshooting guide migration-guide.md - v3 → v4 migration Official Documentation shadcn/ui Vite Setup : https://ui.shadcn.com/docs/installation/vite shadcn/ui Tailwind v4 : https://ui.shadcn.com/docs/tailwind-v4 Tailwind v4 Docs : https://tailwindcss.com/docs Last Updated : 2026-01-20 Skill Version : 3.0.0 Tailwind v4 : 4.1.18 (Latest) Production : WordPress Auditor ( https://wordpress-auditor.webfonts.workers.dev ) Changelog : v3.0.0 (2026-01-20): Major research update - added 3 TIER 1 errors (#6-8), expanded migration guide with community findings (TIER 2), added OKLCH color space section, PostCSS complexity warnings, and migration tool limitations v2.0.1 (2026-01-03): Production verification v2.0.0: Initial release with 5 documented errors
返回排行榜