Building a Design System with Tailwind CSS v4 and React
Why Design Systems Matter
A well-crafted design system is the backbone of any scalable frontend application. It ensures consistency, speeds up development, and makes your codebase maintainable as it grows.
With Tailwind CSS v4's revolutionary CSS-first configuration, building a token-based design system has never been more intuitive. Gone are the days of wrestling with JavaScript config files — now everything lives in your CSS.
Setting Up Your Token System
The key insight is using CSS custom properties as your single source of truth:
@theme inline {
--color-primary: oklch(0.45 0.2 264);
--color-secondary: oklch(0.78 0.14 75);
--radius-lg: 0.625rem;
}Tip
oklch color space gives you perceptually uniform colors — meaning your palette will look consistent across different hues and lightness levels.
Building Your First Component
Start with the smallest building blocks and compose upward:
interface ButtonProps {
variant: "primary" | "secondary" | "ghost"
size: "sm" | "md" | "lg"
children: React.ReactNodeexport function Button({ variant, size, children }: ButtonProps) { return ( <button className={cn(baseStyles, variants[variant], sizes[size])}> {children} </button> ) } ```
Token Architecture
Structure your tokens in three layers:
- Primitive tokens — raw color values, spacing units
- Semantic tokens — purpose-driven aliases like
--color-destructive - Component tokens — scoped to specific components
This layered approach means you can swap entire themes by changing just the primitive layer.
Dark Mode for Free
With oklch and CSS custom properties, dark mode becomes trivial:
.dark {
--color-primary: oklch(0.7 0.18 264);
--color-background: oklch(0.16 0.02 264);
}No JavaScript toggling of individual colors — just swap the entire token set.
editor
UX engineer and accessibility advocate. Specializes in design systems, inclusive design, and CSS architecture. Speaker at multiple web conferences.
Comments (1)
This is exactly what I needed! The oklch color space tip is a game changer for our team's design system. We've been struggling with color consistency across themes.
Related Posts
The Complete Guide to Next.js 16 App Router
Everything you need to know about Next.js 16's App Router — from layouts and loading states to parallel routes and intercepting routes.
Mastering TypeScript Generics: Real-World Patterns
Move beyond basic generics with practical patterns for type-safe APIs, component props, and utility types that you'll use every day.
Accessible Web Forms: A Practical Checklist
A hands-on guide to building forms that work for everyone — covering ARIA patterns, keyboard navigation, error handling, and screen reader testing.