Skill: shadcn
Scope
- •Applies to: Tailwind v4 with shadcn/ui setup, CSS variable architecture, dark mode, theme configuration, component composition patterns, accessibility, form integration
- •Does NOT cover: Tailwind v3, PostCSS configuration
Assumptions
- •Tailwind CSS v4+
- •shadcn/ui latest
- •Vite (use
@tailwindcss/viteplugin) - •React 18+ or Next.js 14+
- •TypeScript 5+
Principles
- •Use
@theme inlineto map CSS variables to Tailwind tokens - •Use
hsl()wrapper for color values in:rootand.dark - •Set
"tailwind.config": ""incomponents.json(empty for v4) - •Delete
tailwind.config.tsif it exists (v4 uses CSS-based config) - •Use
@tailwindcss/viteplugin (not PostCSS) - •Use
cn()utility for conditional classes - •Semantic colors automatically adapt to dark mode (no
dark:variants needed) - •Use
@plugindirective for plugins (not@importorrequire()) - •Compose complex components from smaller shadcn primitives
- •Extend components via wrapper pattern (don't modify originals)
- •Use CVA (class-variance-authority) for variant systems
- •Always use
forwardReffor form-compatible components - •Leverage Radix UI primitives for built-in accessibility
Constraints
MUST
- •Wrap color values with
hsl()in:rootand.dark - •Use
@theme inlineto map all CSS variables - •Set
"tailwind.config": ""incomponents.json - •Delete
tailwind.config.tsif it exists - •Use
@tailwindcss/viteplugin
SHOULD
- •Use semantic color tokens (
--background,--foreground, etc.) - •Use
cn()utility for conditional classes - •Use
@plugindirective for plugins - •Compose components from smaller shadcn primitives
- •Use wrapper pattern to extend components (don't modify originals)
- •Use CVA for variant systems in custom components
- •Use
forwardReffor components that need ref forwarding - •Test accessibility with keyboard navigation and screen readers
- •Use Radix UI primitives for complex interactions (dialogs, dropdowns, etc.)
- •Provide ARIA labels for icon-only buttons and interactive elements
AVOID
- •Putting
:rootor.darkinside@layer base - •Using
.dark { @theme { } }pattern (v4 doesn't support nested @theme) - •Double-wrapping colors (
hsl(var(--background))in body) - •Using
tailwind.config.tsfor theme colors - •Using
@applydirective (deprecated in v4) - •Using
dark:variants for semantic colors - •Using
@importorrequire()for plugins (use@plugin) - •Modifying base shadcn components directly (use wrapper pattern)
- •Building custom dropdowns/dialogs from scratch (use Radix primitives)
- •Relying on color alone for state indication
- •Skipping accessibility testing
Interactions
- •Works with nextjs for App Router setup
- •Uses typescript for type safety
Patterns
CSS Variable Setup
css
/* src/index.css */
@import "tailwindcss";
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
}
:root {
--background: hsl(0 0% 100%);
--foreground: hsl(222.2 84% 4.9%);
}
.dark {
--background: hsl(222.2 84% 4.9%);
--foreground: hsl(210 40% 98%);
}
Vite Configuration
typescript
// vite.config.ts
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
})
Components Config
json
{
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "slate",
"cssVariables": true
}
}
See Templates (including Component Extension) and Architecture for complete setup.
References
- •Architecture - Complete setup pattern
- •Dark Mode - Dark mode implementation
- •Common Gotchas - Common issues and fixes
- •Migration Guide - Migrating from v3
- •Component Patterns - Composition, CVA, extension patterns
- •Accessibility - ARIA, keyboard navigation, screen readers
- •Form Patterns - React Hook Form integration