| 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. Use when this capability is needed. |
| metadata | {"author":"ericgrill"} |
Tailwind Design System (v4)
Build production-ready design systems with Tailwind CSS v4, including CSS-first configuration, design tokens, component variants, responsive patterns, and accessibility.
Note: This skill targets Tailwind CSS v4 (2024+). For v3 projects, refer to the upgrade guide.
When to Use This Skill
- Creating a component library with Tailwind v4
- Implementing design tokens and theming with CSS-first configuration
- Building responsive and accessible components
- Standardizing UI patterns across a codebase
- Migrating from Tailwind v3 to v4
- Setting up dark mode with native CSS features
Key v4 Changes
| v3 Pattern | v4 Pattern |
|---|
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") | CSS @keyframes in @theme + @starting-style for entry animations |
Quick Start
@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-accent: oklch(96% 0.01 264);
--color-accent-foreground: oklch(14.5% );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ;
: ;
: ;
: ;
: fade-in ease-out;
: fade-out ease-in;
: slide-in ease-out;
: slide-out ease-in;
fade-in {
{
: ;
}
{
: ;
}
}
fade-out {
{
: ;
}
{
: ;
}
}
slide-in {
{
: (-);
: ;
}
{
: ();
: ;
}
}
slide-out {
{
: ();
: ;
}
{
: (-);
: ;
}
}
}
dark (&:where(.dark, .dark *));
{
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
: ( );
}
base {
* {
border-border;
}
{
bg-background text-foreground antialiased;
}
}
Core Concepts
1. Design Token Hierarchy
Brand Tokens (abstract)
└── Semantic Tokens (purpose)
└── Component Tokens (specific)
Example:
oklch(45% 0.2 260) → --color-primary → bg-primary
2. Component Architecture
Base styles → Variants → Sizes → States → Overrides
Patterns
Pattern 1: CVA (Class Variance Authority) Components
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap 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 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'size-10',
},
},
defaultVariants: {
: ,
: ,
},
}
)
.<>,
<typeof buttonVariants> {
?:
}
() {
= asChild ? :
(
)
}
< variant= size=></>
Pattern 2: Compound Components (React 19)
import { cn } from '@/lib/utils'
export function Card({
className,
ref,
...props
}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) {
return (
<div
ref={ref}
className={cn(
'rounded-lg border border-border bg-card text-card-foreground shadow-sm',
className
)}
{...props}
/>
)
}
export function CardHeader({
className,
ref,
...props
}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) {
return (
<div
ref={ref}
className={cn('flex flex-col space-y-1.5 p-6', className)}
{...props}
/>
)
}
export function CardTitle({
className,
ref,
...props
}: .<> & { ref?: React.Ref<HTMLHeadingElement> }) {
(
)
}
() {
(
)
}
() {
(
)
}
() {
(
)
}
<>
</>
Pattern 3: Form Components
import { cn } from '@/lib/utils'
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
error?: string
ref?: React.Ref<HTMLInputElement>
}
export function Input({ className, type, error, ref, ...props }: InputProps) {
return (
<div className="relative">
<input
type={type}
className={cn(
'flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ',
&& ' ',
)}
=
=
= ? `${}` }
{}
/>
{error && (
{error}
)}
)
}
{ cva, }
labelVariants = (
)
() {
(
)
}
{ useForm }
{ zodResolver }
{ z }
schema = z.({
: z.().(),
: z.().(, ),
})
() {
{ register, handleSubmit, : { errors } } = ({
: (schema),
})
(
)
}
Pattern 4: Responsive Grid System
import { cn } from '@/lib/utils'
import { cva, type VariantProps } from 'class-variance-authority'
const gridVariants = cva('grid', {
variants: {
cols: {
1: 'grid-cols-1',
2: 'grid-cols-1 sm:grid-cols-2',
3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
5: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-5',
6: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-6',
},
gap: {
none: 'gap-0',
sm: 'gap-2',
md: 'gap-4',
lg: 'gap-6',
xl: 'gap-8',
},
},
defaultVariants: {
cols: 3,
gap: 'md',
},
})
interface GridProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof gridVariants> {}
export () {
(
)
}
containerVariants = (, {
: {
: {
: ,
: ,
: ,
: ,
: ,
: ,
},
},
: {
: ,
},
})
.<>,
<typeof containerVariants> {}
() {
(
)
}
<>
</>
For advanced animation and dark mode patterns, see references/advanced-patterns.md:
- Pattern 5: Native CSS Animations — dialog
@keyframes, native popover API with @starting-style, allow-discrete transitions, and a full DialogContent/DialogOverlay implementation using Radix UI
- Pattern 6: Dark Mode —
ThemeProvider context with localStorage persistence, prefers-color-scheme detection, meta theme-color update, and a ThemeToggle button component
Utility Functions
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export const focusRing = cn(
"focus-visible:outline-none focus-visible:ring-2",
"focus-visible:ring-ring focus-visible:ring-offset-2",
);
export const disabled = "disabled:pointer-events-none disabled:opacity-50";
For advanced v4 CSS patterns, the full v3-to-v4 migration checklist, and complete best practices, see references/advanced-patterns.md:
- Custom
@utility — reusable CSS utilities for decorative lines and text gradients
- Theme modifiers —
@theme inline (reference other CSS vars), @theme static (always output), @import "tailwindcss" theme(static)
- Namespace overrides — clearing default Tailwind color scales with
--color-*: initial
- Semi-transparent variants —
color-mix() for alpha scale generation
- Container queries —
--container-* token definitions
- v3→v4 migration checklist — 10-item checklist covering config, directives, colors, dark mode, animations, React 19 ref changes
- Best practices — full Do's and Don'ts list
Converted and distributed by TomeVault — claim your Tome and manage your conversions.