---
name: tailwind-design-system
description: Build scalable design systems with Tailwind CSS v4, design tokens, component libraries, and responsive patterns. Use when creating component libraries, implementing design systems, or standardizing UI patterns.
enabled: false
source: github:JuanJoseGonGi/skills
imported-from: github:JuanJoseGonGi/skills
---

# Tailwind Design System (v4)

Build production-ready design systems with Tailwind CSS v4's CSS-first configuration, design tokens, CVA component variants, and accessible patterns.

> Targets Tailwind CSS v4 (2024+). For v3, see the [upgrade guide](https://tailwindcss.com/docs/upgrade-guide).

## When to Use

- Creating component libraries with Tailwind v4
- Implementing design tokens and theming via `@theme`
- Building responsive, accessible components
- Standardizing UI patterns across a codebase
- Migrating from v3 to v4

## Key v4 Changes

| v3 | v4 |
| --- | --- |
| `tailwind.config.ts` | `@theme` in CSS |
| `@tailwind base/components/utilities` | `@import "tailwindcss"` |
| `darkMode: "class"` | `@custom-variant dark (&:where(.dark, .dark *))` |
| `theme.extend.colors` | `@theme { --color-*: value }` |
| `require("tailwindcss-animate")` | Native `@keyframes` in `@theme` + `@starting-style` |
| Custom plugins | `@utility` directives |

## Quick Start

```css
@import "tailwindcss";

@theme {
  --color-background: oklch(100% 0 0);
  --color-foreground: oklch(14.5% 0.025 264);
  --color-primary: oklch(14.5% 0.025 264);
  --color-primary-foreground: oklch(98% 0.01 264);
  --color-secondary: oklch(96% 0.01 264);
  --color-secondary-foreground: oklch(14.5% 0.025 264);
  --color-muted: oklch(96% 0.01 264);
  --color-muted-foreground: oklch(46% 0.02 264);
  --color-destructive: oklch(53% 0.22 27);
  --color-destructive-foreground: oklch(98% 0.01 264);
  --color-border: oklch(91% 0.01 264);
  --color-ring: oklch(14.5% 0.025 264);

  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;

  --animate-fade-in: fade-in 0.2s ease-out;
  --animate-slide-in: slide-in 0.3s ease-out;

  @keyframes fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
  }
  @keyframes slide-in {
    from { transform: translateY(-0.5rem); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
  }
}

@custom-variant dark (&:where(.dark, .dark *));

@layer base {
  * { @apply border-border; }
  body { @apply bg-background text-foreground antialiased; }
}
```

Full theme with dark mode overrides, all semantic tokens, and animation keyframes: see **references/theme-config.md**.

## Core Concepts

### Design Token Hierarchy

```
Brand Tokens (abstract values)
  └── Semantic Tokens (purpose: --color-primary)
      └── Component Tokens (specific: bg-primary)
```

Use OKLCH for perceptual uniformity. Define semantic names (`primary`, `destructive`, `muted`) rather than raw color scales.

### Component Architecture

```
Base styles → Variants (CVA) → Sizes → States → className overrides
```

### The `cn()` Utility

```typescript
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}
```

## CVA Component Pattern

The core pattern for type-safe variant components:

```typescript
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'

const buttonVariants = cva(
  'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground hover:bg-primary/90',
        destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
        outline: 'border border-border bg-background hover:bg-accent hover:text-accent-foreground',
        secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
        ghost: 'hover:bg-accent hover:text-accent-foreground',
        link: 'text-primary underline-offset-4 hover:underline',
      },
      size: {
        default: 'h-10 px-4 py-2',
        sm: 'h-9 px-3',
        lg: 'h-11 px-8',
        icon: 'size-10',
      },
    },
    defaultVariants: { variant: 'default', size: 'default' },
  }
)

// React 19: ref is a regular prop, no forwardRef needed
export function Button({
  className, variant, size, asChild = false, ref, ...props
}: ButtonProps & { ref?: React.Ref<HTMLButtonElement> }) {
  const Comp = asChild ? Slot : 'button'
  return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
}
```

Full Button, Card, Input, Label, Grid, Container, and Dialog examples: see **references/component-patterns.md**.

## Dark Mode

v4 uses `@custom-variant` + CSS variable overrides on `.dark`:

```css
@custom-variant dark (&:where(.dark, .dark *));

.dark {
  --color-background: oklch(14.5% 0.025 264);
  --color-foreground: oklch(98% 0.01 264);
  /* ... override all semantic tokens ... */
}
```

ThemeProvider, ThemeToggle, and system-preference detection: see **references/dark-mode.md**.

## Advanced v4 Features

### `@utility` — Custom Utilities

```css
@utility text-gradient {
  @apply bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent;
}
```

### Theme Modifiers

```css
@theme inline { --font-sans: var(--font-inter), system-ui; }  /* reference other vars */
@theme static { --color-brand: oklch(65% 0.15 240); }         /* always emit */
```

### Namespace Overrides

```css
@theme {
  --color-*: initial;  /* clear all default colors */
  --color-primary: oklch(45% 0.2 260);
}
```

### Semi-transparent Variants

```css
@theme {
  --color-primary-50: color-mix(in oklab, var(--color-primary) 5%, transparent);
}
```

### Container Queries

```css
@theme {
  --container-xs: 20rem;
  --container-sm: 24rem;
}
```

### Native Popover Animations

```css
[popover] {
  transition: opacity 0.2s, transform 0.2s, display 0.2s allow-discrete;
  opacity: 0; transform: scale(0.95);
}
[popover]:popover-open { opacity: 1; transform: scale(1); }
@starting-style {
  [popover]:popover-open { opacity: 0; transform: scale(0.95); }
}
```

Full advanced patterns with dialog keyframes and more: see **references/advanced-v4-patterns.md**.

## v3 → v4 Migration Checklist

- [ ] Replace `tailwind.config.ts` with CSS `@theme` block
- [ ] Change `@tailwind base/components/utilities` → `@import "tailwindcss"`
- [ ] Move colors to `@theme { --color-*: value }`
- [ ] Replace `darkMode: "class"` → `@custom-variant dark`
- [ ] Move `@keyframes` inside `@theme` blocks
- [ ] Replace `tailwindcss-animate` with native CSS animations
- [ ] Update `h-10 w-10` → `size-10`
- [ ] Remove `forwardRef` (React 19 passes ref as prop)
- [ ] Consider OKLCH colors over HSL
- [ ] Replace custom plugins with `@utility`

## Best Practices

**Do:**
- Use `@theme` blocks — CSS-first config is v4's core pattern
- Use OKLCH — better perceptual uniformity than HSL
- Compose variants with CVA — type-safe, composable
- Use semantic tokens — `bg-primary` not `bg-blue-500`
- Use `size-*` — shorthand for equal `w-*`/`h-*`
- Include accessibility — ARIA attributes, visible focus rings, `sr-only` labels

**Don't:**
- Use `tailwind.config.ts` — use CSS `@theme`
- Use `@tailwind` directives — use `@import "tailwindcss"`
- Use `forwardRef` — React 19 ref-as-prop
- Use arbitrary values — extend `@theme` instead
- Hardcode colors — use semantic tokens
- Skip dark mode testing

## Reference Files

| File | Contents |
| --- | --- |
| `references/theme-config.md` | Full OKLCH theme, dark mode overrides, token hierarchy, color-mix, namespace overrides |
| `references/component-patterns.md` | Button, Card, Input, Label, Grid, Container, Dialog — complete implementations |
| `references/dark-mode.md` | ThemeProvider, ThemeToggle, system preference detection |
| `references/advanced-v4-patterns.md` | `@utility`, theme modifiers, container queries, popover/dialog animations |

## External Resources

- [Tailwind CSS v4 Docs](https://tailwindcss.com/docs)
- [CVA](https://cva.style/docs)
- [shadcn/ui](https://ui.shadcn.com/)
- [Radix Primitives](https://www.radix-ui.com/primitives)
