name: shadcn-tailwind
description: Build UIs with Tailwind CSS v4 and shadcn/ui. Covers CSS variables with OKLCH colors, component variants with CVA, responsive design, dark mode, and Tailwind v4.2 features. Supports Radix UI and Base UI primitives, CLI 3.0, and visual styles. Use when building interfaces with Tailwind, styling shadcn/ui components, implementing themes, or working with utility-first CSS. Triggers on tailwind, shadcn, utility classes, CSS variables, OKLCH, component styling, theming, dark mode, radix ui.
metadata:
version: "0.1.1"
Styling with Tailwind CSS Build accessible UIs using Tailwind CSS v4 utility classes and shadcn/ui component patterns. Tailwind v4 uses CSS-first configuration only - never create or modify tailwind.config.js/tailwind.config.ts. Supports Radix UI (default) or Base UI as primitive libraries.
Critical Rules
No tailwind.config.js - CSS-First Only Tailwind v4 configures everything in CSS. Migrate any JS/TS config:
theme.extend.colors β @theme { --color-*: ... }
plugins β @plugin "..." or @utility
content β @source "..."
tailwindcss-animate β @import "tw-animate-css"
@layer utilities β @utility name { ... }
Always Use Semantic Color Tokens
// CORRECT - respects themes and dark mode
// WRONG - breaks theming
Always pair bg-* with text-*-foreground. Extend with success/warning/info in theming.md .
Never Build Class Names Dynamically
// WRONG - breaks Tailwind scanner
bg-${color}-500}>
// CORRECT - complete strings via lookup
const colorMap = { red: "bg-red-500", blue: "bg-blue-500" } as const
cn() Merge Order Defaults first, consumer className last (tailwind-merge last-wins):
className={cn(buttonVariants({ variant, size }), className)} // correct
className={cn(className, buttonVariants({ variant, size }))} // wrong
Animation Performance
// WRONG - transition-all causes layout thrashing
// CORRECT - transition only what changes
// CORRECT - respect reduced motion
@theme vs @theme inline
@theme - static tokens, overridable by plugins
@theme inline - references CSS variables, follows dark mode changes
@theme { --color-brand: oklch(0.6 0.2 250); } /* static */
@theme inline { --color-primary: var(--primary); } /* dynamic */
See components.md for more pitfalls and theming.md for color system reference.
Core Patterns
CSS Variables for Theming shadcn/ui uses semantic CSS variables mapped to Tailwind utilities:
/* globals.css - Light mode */
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--border: oklch(0.922 0 0);
--radius: 0.5rem;
}/* Dark mode */
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
}
/* Tailwind v4: Map variables */
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
}
Usage in components:
// Background colors omit the "-background" suffix
Component Authoring Pattern Components use plain functions with data-slot attributes (React 19 - no forwardRef):
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 px-3 text-xs",
lg: "h-10 px-8",
icon: "size-9",
},
},
defaultVariants: { variant: "default", size: "default" },
}
)
// Plain function with React.ComponentProps (not forwardRef)
function Button({
className,
variant,
size,
...props
}: React.ComponentProps<"button"> & VariantProps) {
return (
)
}
// Usage
Click me
Icon spacing with data-icon:
Generating...
Save Changes
Responsive Design Mobile-first breakpoints:
// Stack on mobile, grid on tablet+
// Hide on mobile
// Different layouts per breakpoint
// Responsive text sizes
Container Queries First-class in Tailwind v4, no plugin needed:
Responds to container width, not viewport
// Named containers
Dark Mode
// Use dark: prefix - but prefer semantic colors over manual dark: overrides
// auto dark mode
// manual override
// Use next-themes for toggle: useTheme() β setTheme("dark" | "light")
// Always add suppressHydrationWarning to to prevent flash
Common Component Patterns
Card
Form Field
Badge
const badgeVariants = cva(
"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors",
{
variants: {
variant: {
default: "border-transparent bg-primary text-primary-foreground shadow",
secondary: "border-transparent bg-secondary text-secondary-foreground",
destructive: "border-transparent bg-destructive text-destructive-foreground",
outline: "text-foreground",
},
},
}
)
Layout Patterns
Centered Layout
Sidebar Layout
Dashboard Grid
Wide card
Regular
Regular
Full width
Accessibility Patterns
Focus Visible
Screen Reader Only
Close dialog
Disabled States
Tailwind v4 Features
CSS-First Configuration
@import "tailwindcss";/* Custom utilities (replaces @layer utilities) */
@utility tab-highlight-none {
-webkit-tap-highlight-color: transparent;
}
/* Custom variants */
@custom-variant pointer-fine (@media (pointer: fine));
/* Source control */
@source inline("{hover:,}bg-red-{50,100,200}");
@source not "./legacy";
@theme Directive
@theme {
--color-primary: oklch(0.205 0 0);
--font-sans: "Inter", system-ui;
}/* With CSS variables (shadcn/ui pattern) */
@theme inline {
--color-primary: var(--primary);
}
Animation
@import "tw-animate-css";
v4.1 Features
// Text shadows
// Gradient masks for fade effects
Fades to transparent at bottom
// Pointer-aware sizing
// Form validation after user interaction
// Overflow wrap for long strings
verylongwordthatneedstowrap
v4.2 Features (February 2026)
// Logical block properties (RTL/writing-mode aware)
// Logical sizing (replaces w-*/h-* for logical layouts)
// Font feature settings
Tabular numbers
// New color palettes: mauve, olive, mist, taupe
Deprecation: start-*/end-* deprecated in favor of inset-s-*/inset-e-*.
OKLCH Colors All shadcn/ui colors use OKLCH format: oklch(lightness chroma hue). Lightness 0-1, chroma 0-0.4 (0 = gray), hue 0-360. Base palettes: Neutral, Zinc, Slate, Stone, Gray. See theming.md for complete palettes and OKLCH reference.
Best Practices
Prefer Semantic Colors
// Good - uses theme
// Avoid - hardcoded
Group Related Utilities
Avoid Arbitrary Values
// Prefer design tokens
// Avoid when unnecessary
Installation & CLI
# Create new project with visual style + primitive selection
npx shadcn create
Initialize in existing project
pnpm dlx shadcn@latest init
Add components
pnpm dlx shadcn@latest add button card form
Add from community registries
npx shadcn add @acme/button @internal/auth-system
View/search registries
npx shadcn view @acme/auth-system
npx shadcn search @tweakcn -q "dark"
npx shadcn list @acme
Add MCP server for AI integration
npx shadcn@latest mcp init
Update existing components
pnpm dlx shadcn@latest add button --overwrite
Visual Styles npx shadcn create offers 5 built-in visual styles:
Vega - Classic shadcn/ui look
Nova - Compact, reduced padding
Maia - Soft and rounded, generous spacing
Lyra - Boxy and sharp, pairs with mono fonts
Mira - Dense, for data-heavy interfacesThese rewrite component code (not just CSS variables) to match the selected style.
Troubleshooting Colors not updating: Check CSS variable in globals.css β verify @theme inline includes the mapping β clear build cache.
Dark mode flash on load: Add suppressHydrationWarning to tag and ensure ThemeProvider wraps app with attribute="class".
Found tailwind.config.js: Delete it. Run npx @tailwindcss/upgrade to auto-migrate to CSS-first config. All customization belongs in your CSS file via @theme, @utility, @plugin.
Classes not detected: Check @source directives cover your component paths. Never construct class names dynamically (see Critical Rules).
Component Patterns For detailed component patterns see components.md :
Composition : asChild pattern, data-slot attributes
Typography : Heading scales, prose styles, inline code
Forms : React Hook Form + Zod, Field component with FieldSet/FieldGroup
Icons : Lucide icons with data-icon attributes
Inputs : OTP, file, grouped inputs
Dialogs : Modal patterns and composition
Data Tables : TanStack table integration
Toasts : Sonner notifications
Pitfalls : cn() order, form defaultValues, dialog nesting, sticky, server/client
Resources See theming.md for complete color system reference:
@theme vs @theme inline (critical for dark mode)
Status color extensions (success, warning, info)
Z-index scale and animation tokens
All base palettes (Neutral, Zinc, Slate, Stone, Gray)
Summary Key concepts:
v4 CSS-first only - no tailwind.config.js, all config in CSS
Semantic colors only - never use raw palette (bg-blue-500), always bg-primary
Always pair bg-* with text-*-foreground
Never build class names dynamically - use object lookup with complete strings
cn() order - defaults first, consumer className last
No transition-all - transition only specific properties
@theme inline for dynamic theming, @theme for static tokens
Author components as plain functions with data-slot (React 19)
Apply CVA for component variants
Use motion-safe: / motion-reduce: for animations
Choose Radix UI or Base UI as primitive library This skill targets Tailwind CSS v4.2 with shadcn/ui. For component-specific examples, see components.md . For color system, see theming.md .
π Tips & Best Practices
Prefer Semantic Colors
// Good - uses theme
// Avoid - hardcoded
Group Related Utilities
Avoid Arbitrary Values
// Prefer design tokens
// Avoid when unnecessary
BytesAgain
Discover the best AI agent skills for your workflow.
Β© 2026 BytesAgain. All rights reserved.
BytesAgain is an independent skill directory. We index and link to third-party content (ClawHub, GitHub, LobeHub, Dify, etc.) for informational purposes only. All trademarks, skill names, and content are the property of their respective owners. BytesAgain does not claim ownership of any indexed content.
π¬