Back to UI/UX Design

tailwind-v4-shadcn

tailwind cssshadcn uireactfrontendvitecss frameworkui componentsdevelopment workflow
⭐ 860πŸ“„ MITπŸ•’ 2026-06-11Source β†—

Install this skill

npx skills add jezweb/claude-skills

Works across Claude Code, Cursor, Codex, Copilot & Antigravity

This configuration standardizes the integration of shadcn/ui with Tailwind CSS v4. Unlike legacy versions, v4 shifts away from traditional configuration files, opting for a CSS-first architecture. This implementation centers on the @theme inline directive to register custom CSS variables into the Tailwind utility system. By removing tailwind.config.ts and mapping semantic color variables directly within the stylesheet, developers achieve a cleaner build process. This setup ensures that semantic design tokens remain synced across light and dark modes without requiring complex variants. It replaces the old PostCSS-based setup with the @tailwindcss/vite plugin, optimizing build performance and ensuring that shadcn components render correctly using native CSS layers and modern animation utilities.

When to Use This Skill

  • β€’Setting up a greenfield project using Shadcn and Tailwind v4
  • β€’Migrating an existing Tailwind v3 project to the v4 architecture
  • β€’Standardizing theme tokens across complex multi-page applications
  • β€’Configuring automated color swapping for site-wide dark mode

How to Invoke This Skill

Example prompts that trigger this skill in Claude Code, Cursor, or Antigravity:

  • β€œSetup shadcn with Tailwind v4
  • β€œHow to configure components.json for Tailwind v4
  • β€œMap CSS variables to Tailwind v4 utilities
  • β€œConfigure theme-provider for Tailwind v4 dark mode
  • β€œFix background colors not working in Tailwind v4

Pro Tips

  • πŸ’‘Always follow the "Four-Step Architecture" precisely to avoid theme breakage and ensure correct variable application.
  • πŸ’‘Regularly check `shadcn@latest` documentation for updates, as `components.json` configurations can evolve.
  • πŸ’‘Utilize the `@` alias in `vite.config.ts` for cleaner imports, especially with shadcn/ui components.

What this skill does

  • β€’Replaces legacy tailwind.config.ts with CSS-native variable mapping
  • β€’Uses @theme inline to register semantic colors as Tailwind utilities
  • β€’Integrates tw-animate-css for native-feeling motion
  • β€’Automates dark mode behavior via CSS root variable switching
  • β€’Supports Vite-based builds with the dedicated @tailwindcss/vite plugin

When not to use it

  • βœ•Projects requiring heavy legacy PostCSS plugin dependencies
  • βœ•Applications restricted to Tailwind v3 or older runtime requirements
  • βœ•Simple static sites that do not require reusable component libraries

Example workflow

  1. Install tailwindcss v4 and the vite plugin via pnpm
  2. Delete existing tailwind.config.ts files from the root
  3. Define semantic HSL variables in your CSS entry point
  4. Map these variables within the @theme inline block
  5. Initialize shadcn and update components.json with empty tailwind config
  6. Wrap the root application component with a ThemeProvider

Prerequisites

  • –Node.js environment
  • –Vite project architecture
  • –Basic familiarity with CSS variables

Pitfalls & limitations

  • !Double-wrapping colors in hsl() inside CSS layers causes failures
  • !Ignoring the @theme inline mapping results in missing utility classes
  • !Nesting @theme inside .dark classes is unsupported in v4
  • !Using deprecated @apply rules for base styles

FAQ

Why is the tailwind.config field in components.json empty?
Tailwind v4 manages theme tokens through CSS variables rather than JavaScript objects. Leaving this blank tells shadcn to skip looking for a missing config file.
Can I still use tailwindcss-animate?
No, shadcn/ui has migrated to tw-animate-css for v4 compatibility. Using the old package will cause import errors.
Why don't my dark: variants work anymore?
In this v4 architecture, semantic variables update automatically based on the class applied to the root. You should rely on variable mapping rather than explicit dark: classes.

How it compares

This workflow replaces the manual, fragmented configuration of v3 with a unified CSS-only approach, eliminating the need for complex PostCSS plugins and JS-based theme definitions.

Source & trust

⭐ 860 starsπŸ“„ MITπŸ•’ Updated 2026-06-11
πŸ“„ Full skill instructions β€” original source: jezweb/claude-skills
# Tailwind v4 + shadcn/ui Production Stack

**Production-tested**: WordPress Auditor (https://wordpress-auditor.webfonts.workers.dev)
**Last Updated**: 2026-01-20
**Versions**: [email protected], @tailwindcss/[email protected]
**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:

1. Wrap colors with hsl() in :root/.dark: --bg: hsl(0 0% 100%);
2. Use @theme inline to map all CSS variables
3. Set "tailwind.config": "" in components.json
4. Delete tailwind.config.ts if exists
5. Use @tailwindcss/vite plugin (NOT PostCSS)

### ❌ Never Do:

1. Put :root/.dark inside @layer base (causes cascade issues)
2. Use .dark { @theme { } } pattern (v4 doesn't support nested @theme)
3. Double-wrap colors: hsl(var(--background))
4. Use tailwind.config.ts for theme (v4 ignores it)
5. Use @apply directive (deprecated in v4, see error #7)
6. Use dark: variants for semantic colors (auto-handled)
7. Use @apply with @layer base or @layer components classes (v4 breaking change - use @utility instead) | [Source](https://github.com/tailwindlabs/tailwindcss/discussions/17082)
8. Wrap ANY styles in @layer base without understanding CSS layer ordering (see error #8) | [Source](https://github.com/tailwindlabs/tailwindcss/discussions/16002)

---

## 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


---

### 2. ❌ 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 */
}


---

### 3. ❌ Dark Mode Not Switching

**Error**: Theme stays light/dark

**Cause**: Missing ThemeProvider

**Solution**:
1. Create ThemeProvider (see templates/theme-provider.tsx)
2. Wrap app in main.tsx
3. Verify .dark class toggles on <html> 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](https://github.com/tailwindlabs/tailwindcss/discussions/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](https://github.com/tailwindlabs/tailwindcss/discussions/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: 1rem 0.5rem;
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](https://github.com/tailwindlabs/tailwindcss/discussions/16002) | [Discussion #18123](https://github.com/tailwindlabs/tailwindcss/discussions/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 <ThemeProvider> |
| 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](https://tailwindcss.com/blog/tailwindcss-v4) | [OKLCH Migration Guide](https://andy-cinquin.com/blog/migration-oklch-tailwind-css-4-0)

**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
</div>
</div>


**Line Clamp** (built-in as of v3.3):
<p className="line-clamp-3">Truncate to 3 lines with ellipsis...</p>
<p className="line-clamp-[8]">Arbitrary values supported</p>
<p className="line-clamp-(--teaser-lines)">CSS variable support</p>


**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 }}</article>


**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</div>
</div>


**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](https://medium.com/better-dev-nextjs-react/tailwind-v4-migration-from-javascript-config-to-css-first-in-2025-ff3f59b215ca) | [GitHub Discussion #16642](https://github.com/tailwindlabs/tailwindcss/discussions/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](https://github.com/tailwindlabs/tailwindcss/discussions/16517) | [Medium: Migration Problems](https://medium.com/better-dev-nextjs-react/tailwind-v4-migration-from-javascript-config-to-css-first-in-2025-ff3f59b215ca)

**Impact**:
- All headings (<h1> through <h6>) 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 */}
</article>


**Option 2: Add custom base styles**:
@layer base {
h1 { @apply text-4xl font-bold mb-4; }
h2 { @apply text-3xl font-bold mb-3; }
h3 { @apply text-2xl 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](https://medium.com/better-dev-nextjs-react/tailwind-v4-migration-from-javascript-config-to-css-first-in-2025-ff3f59b215ca) | [GitHub Discussion #15764](https://github.com/tailwindlabs/tailwindcss/discussions/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](https://medium.com/better-dev-nextjs-react/tailwind-v4-migration-from-javascript-config-to-css-first-in-2025-ff3f59b215ca)

- ring class is now thinner
- Use ring-3 to match v3 appearance

// v3: 3px ring
<button className="ring">Button</button>

// v4: 1px ring (thinner)
<button className="ring">Button</button>

// Match v3 appearance
<button className="ring-3">Button</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


---

---
paths: "**/*.css", "**/*.tsx", "**/*.jsx", tailwind.config.*, components.json, postcss.config.*
---

# Tailwind v4 + shadcn/ui Corrections

Claude's training may reference Tailwind v3 patterns. This project uses **Tailwind v4** with different syntax.

## Critical Differences from v3

### Configuration
- **No tailwind.config.ts** - v4 uses CSS-first config with @theme blocks
- **No PostCSS setup** - Use @tailwindcss/vite plugin instead
- **components.json** must have "config": "" (empty string)

### CSS Syntax
/* ❌ v3 (Claude may suggest this) */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* βœ… v4 (use this) */
@import "tailwindcss";


### Theme Configuration
/* ❌ v3 - tailwind.config.ts */
theme: { colors: { primary: '#3b82f6' } }

/* βœ… v4 - in CSS file */
@theme inline {
--color-primary: var(--primary);
--color-background: var(--background);
}


### Animations Package
# ❌ v3 package (deprecated for v4)
pnpm add tailwindcss-animate

# βœ… v4 package
pnpm add -D tw-animate-css


/* βœ… v4 import */
@import "tailwindcss";
@import "tw-animate-css";


### Plugins
/* ❌ v3 - require() in config */
plugins: [require('@tailwindcss/typography')]

/* βœ… v4 - @plugin directive in CSS */
@plugin "@tailwindcss/typography";


### @apply Directive
/* ❌ Deprecated in v4 */
.btn { @apply px-4 py-2 bg-primary; }

/* βœ… Use direct classes or CSS */
.btn { padding: 0.5rem 1rem; background-color: var(--primary); }


## Variable Architecture

CSS variables must follow this structure:

/* 1. Define at root (NOT inside @layer base) */
:root {
--background: hsl(0 0% 100%); /* hsl() wrapper required */
--primary: hsl(221.2 83.2% 53.3%);
}

.dark {
--background: hsl(222.2 84% 4.9%);
--primary: hsl(217.2 91.2% 59.8%);
}

/* 2. Map to Tailwind utilities */
@theme inline {
--color-background: var(--background);
--color-primary: var(--primary);
}

/* 3. Apply base styles (NO hsl wrapper here) */
@layer base {
body {
background-color: var(--background);
color: var(--foreground);
}
}


## Dark Mode

- No dark: variants needed for semantic colors - theme switches automatically
- Just use bg-background, text-foreground, etc.
- ThemeProvider toggles .dark class on <html> element

## Quick Fixes

| If Claude suggests... | Use instead... |
|----------------------|----------------|
| @tailwind base | @import "tailwindcss" |
| tailwind.config.ts | @theme inline in CSS |
| tailwindcss-animate | tw-animate-css |
| require('@plugin') | @plugin "@plugin" |
| @apply | Direct CSS or utility classes |
| hsl(var(--color)) | var(--color) (already has hsl) |

How to Use This Skill Unit

Option A: Project-Specific (Recommended)

  1. Click "Download" above
  2. In your project, create the directory: .agent/skills/tailwind-v4-shadcn/
  3. Save the file as SKILL.md
  4. The agent will automatically discover the skill based on its description.

Option B: Global Installation (All Agents)

Save the file to these locations to make it available across all projects:

  • Claude Code: ~/.claude/skills/jezweb/claude-skills/tailwind-v4-shadcn/SKILL.md
  • Cursor: ~/.cursor/skills/jezweb/claude-skills/tailwind-v4-shadcn/SKILL.md
  • Antigravity: ~/.gemini/antigravity/skills/jezweb/claude-skills/tailwind-v4-shadcn/SKILL.md

πŸš€ Install with CLI:
npx skills add jezweb/claude-skills

Read the Master Guide: Mastering Agent Skills β†’

Recommended Rules

View more rules β†’

Recommended Workflows

View more workflows β†’

Recommended MCP Servers

View more MCP servers β†’

Take It Further

Maximize your productivity with these powerful resources

πŸ“‹

Define Your Standards

Set up coding standards to ensure this workflow produces consistent, high-quality results.

Browse Rules Library
πŸ“–

Master Workflows

Learn how to create custom workflows, use Turbo Mode, and build your automation library.

Complete Guide

How to use this Skill in Claude Code & Cursor

For Claude Code (CLI)

To use this skill in Claude Code, copy the rule content into your project's custom instructions or follow our Add-Skill CLI guide. This ensures Claude follows your standards during every code generation.

For Cursor & Windsurf

For Cursor or Windsurf, individual skills are best used in the "Rules for AI" section. This specific unit helps the agent avoid ui/ux design issues, leading to cleaner, more efficient code.

Why the skill format matters: the standardized Agent Skills format lets your AI agent load detailed instructions only when they are relevant, keeping your prompt clean while improving results.

Source & attribution

This skill is categorized under UI/UX Design and is published by JezWeb, maintained in jezweb/claude-skills.

← Browse All Agent Skills
Sponsored AI assistant. Recommendations may be paid.