
Tailwind Design System
- 56.4k installs
- 38.3k repo stars
- Updated July 22, 2026
- wshobson/agents
tailwind-design-system is a Claude Code skill that generates scalable Tailwind CSS v4 design systems with tokens, variants, and accessibility.
About
tailwind-design-system is an agent skill for building production-ready design systems on Tailwind CSS v4 using CSS-first configuration, design tokens, component variants, responsive patterns, and accessibility defaults.
- CSS-first @theme configuration replacing tailwind.config.ts
- Native dark mode using @custom-variant instead of darkMode class
- Production-ready component library with design tokens and variants
Tailwind Design System by the numbers
- 56,358 all-time installs (skills.sh)
- +1,293 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #11 of 2,277 Frontend Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/wshobson/agents --skill tailwind-design-systemAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 56.4k |
|---|---|
| repo stars | ★ 38.3k |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 22, 2026 |
| Repository | wshobson/agents ↗ |
How do you build a Tailwind CSS v4 design system?
Generate consistent, scalable Tailwind v4 design systems with tokens, component variants, responsive patterns, and accessibility.
Who is it for?
Frontend developers standardizing React or web UI with Tailwind v4 tokens, variants, and component libraries.
Skip if: Projects locked on Tailwind v3 without upgrade plans, or teams needing Figma-only design specs.
When should I use this skill?
User asks for Tailwind v4 design tokens, component library setup, design system standardization, or accessible Tailwind patterns.
What you get
Tailwind v4 token config, component variant patterns, responsive utility conventions, and accessible UI component scaffolding
- Design token configuration
- Component variant library patterns
Files
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
/* app.css - Tailwind v4 CSS-first configuration */
@import "tailwindcss";
/* Define your theme with @theme */
@theme {
/* Semantic color tokens using OKLCH for better color perception */
--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% 0.025 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);
--color-card: oklch(100% 0 0);
--color-card-foreground: oklch(14.5% 0.025 264);
/* Ring offset for focus states */
--color-ring-offset: oklch(100% 0 0);
/* Radius tokens */
--radius-sm: 0.25rem;
--radius-md: 0.375rem;
--radius-lg: 0.5rem;
--radius-xl: 0.75rem;
/* Animation tokens - keyframes inside @theme are output when referenced by --animate-* variables */
--animate-fade-in: fade-in 0.2s ease-out;
--animate-fade-out: fade-out 0.2s ease-in;
--animate-slide-in: slide-in 0.3s ease-out;
--animate-slide-out: slide-out 0.3s ease-in;
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes slide-in {
from {
transform: translateY(-0.5rem);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slide-out {
from {
transform: translateY(0);
opacity: 1;
}
to {
transform: translateY(-0.5rem);
opacity: 0;
}
}
}
/* Dark mode variant - use @custom-variant for class-based dark mode */
@custom-variant dark (&:where(.dark, .dark *));
/* Dark mode theme overrides */
.dark {
--color-background: oklch(14.5% 0.025 264);
--color-foreground: oklch(98% 0.01 264);
--color-primary: oklch(98% 0.01 264);
--color-primary-foreground: oklch(14.5% 0.025 264);
--color-secondary: oklch(22% 0.02 264);
--color-secondary-foreground: oklch(98% 0.01 264);
--color-muted: oklch(22% 0.02 264);
--color-muted-foreground: oklch(65% 0.02 264);
--color-accent: oklch(22% 0.02 264);
--color-accent-foreground: oklch(98% 0.01 264);
--color-destructive: oklch(42% 0.15 27);
--color-destructive-foreground: oklch(98% 0.01 264);
--color-border: oklch(22% 0.02 264);
--color-ring: oklch(83% 0.02 264);
--color-card: oklch(14.5% 0.025 264);
--color-card-foreground: oklch(98% 0.01 264);
--color-ring-offset: oklch(14.5% 0.025 264);
}
/* Base styles */
@layer base {
* {
@apply border-border;
}
body {
@apply 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-primary2. Component Architecture
Base styles → Variants → Sizes → States → OverridesDetailed patterns and worked examples
Detailed pattern documentation lives in references/details.md. Read that file when the navigation tier above is insufficient.
Tailwind Design System: Advanced Patterns
Advanced Tailwind CSS v4 patterns including animations, dark mode theming, custom utilities, theme modifiers, namespace overrides, and the v3-to-v4 migration checklist.
Pattern 5: Native CSS Animations (v4)
/* In your CSS file - native @starting-style for entry animations */
@theme {
--animate-dialog-in: dialog-fade-in 0.2s ease-out;
--animate-dialog-out: dialog-fade-out 0.15s ease-in;
}
@keyframes dialog-fade-in {
from {
opacity: 0;
transform: scale(0.95) translateY(-0.5rem);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
@keyframes dialog-fade-out {
from {
opacity: 1;
transform: scale(1) translateY(0);
}
to {
opacity: 0;
transform: scale(0.95) translateY(-0.5rem);
}
}
/* Native popover animations using @starting-style */
[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);
}
}// components/ui/dialog.tsx - Using native popover API
import * as DialogPrimitive from '@radix-ui/react-dialog'
import { cn } from '@/lib/utils'
const DialogPortal = DialogPrimitive.Portal
export function DialogOverlay({
className,
ref,
...props
}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & {
ref?: React.Ref<HTMLDivElement>
}) {
return (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
'fixed inset-0 z-50 bg-black/80',
'data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out',
className
)}
{...props}
/>
)
}
export function DialogContent({
className,
children,
ref,
...props
}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
ref?: React.Ref<HTMLDivElement>
}) {
return (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
'fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border border-border bg-background p-6 shadow-lg sm:rounded-lg',
'data-[state=open]:animate-dialog-in data-[state=closed]:animate-dialog-out',
className
)}
{...props}
>
{children}
</DialogPrimitive.Content>
</DialogPortal>
)
}Pattern 6: Dark Mode with CSS (v4)
// providers/ThemeProvider.tsx - Simplified for v4
'use client'
import { createContext, useContext, useEffect, useState } from 'react'
type Theme = 'dark' | 'light' | 'system'
interface ThemeContextType {
theme: Theme
setTheme: (theme: Theme) => void
resolvedTheme: 'dark' | 'light'
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined)
export function ThemeProvider({
children,
defaultTheme = 'system',
storageKey = 'theme',
}: {
children: React.ReactNode
defaultTheme?: Theme
storageKey?: string
}) {
const [theme, setTheme] = useState<Theme>(defaultTheme)
const [resolvedTheme, setResolvedTheme] = useState<'dark' | 'light'>('light')
useEffect(() => {
const stored = localStorage.getItem(storageKey) as Theme | null
if (stored) setTheme(stored)
}, [storageKey])
useEffect(() => {
const root = document.documentElement
root.classList.remove('light', 'dark')
const resolved = theme === 'system'
? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
: theme
root.classList.add(resolved)
setResolvedTheme(resolved)
// Update meta theme-color for mobile browsers
const metaThemeColor = document.querySelector('meta[name="theme-color"]')
if (metaThemeColor) {
metaThemeColor.setAttribute('content', resolved === 'dark' ? '#09090b' : '#ffffff')
}
}, [theme])
return (
<ThemeContext.Provider value={{
theme,
setTheme: (newTheme) => {
localStorage.setItem(storageKey, newTheme)
setTheme(newTheme)
},
resolvedTheme,
}}>
{children}
</ThemeContext.Provider>
)
}
export const useTheme = () => {
const context = useContext(ThemeContext)
if (!context) throw new Error('useTheme must be used within ThemeProvider')
return context
}
// components/ThemeToggle.tsx
import { Moon, Sun } from 'lucide-react'
import { useTheme } from '@/providers/ThemeProvider'
export function ThemeToggle() {
const { resolvedTheme, setTheme } = useTheme()
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')}
>
<Sun className="size-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute size-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
)
}Advanced v4 Patterns
Custom Utilities with @utility
Define reusable custom utilities:
/* Custom utility for decorative lines */
@utility line-t {
@apply relative before:absolute before:top-0 before:-left-[100vw] before:h-px before:w-[200vw] before:bg-gray-950/5 dark:before:bg-white/10;
}
/* Custom utility for text gradients */
@utility text-gradient {
@apply bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent;
}Theme Modifiers
/* Use @theme inline when referencing other CSS variables */
@theme inline {
--font-sans: var(--font-inter), system-ui;
}
/* Use @theme static to always generate CSS variables (even when unused) */
@theme static {
--color-brand: oklch(65% 0.15 240);
}
/* Import with theme options */
@import "tailwindcss" theme(static);Namespace Overrides
@theme {
/* Clear all default colors and define your own */
--color-*: initial;
--color-white: #fff;
--color-black: #000;
--color-primary: oklch(45% 0.2 260);
--color-secondary: oklch(65% 0.15 200);
/* Clear ALL defaults for a minimal setup */
/* --*: initial; */
}Semi-transparent Color Variants
@theme {
/* Use color-mix() for alpha variants */
--color-primary-50: color-mix(in oklab, var(--color-primary) 5%, transparent);
--color-primary-100: color-mix(
in oklab,
var(--color-primary) 10%,
transparent
);
--color-primary-200: color-mix(
in oklab,
var(--color-primary) 20%,
transparent
);
}Container Queries
@theme {
--container-xs: 20rem;
--container-sm: 24rem;
--container-md: 28rem;
--container-lg: 32rem;
}v3 to v4 Migration Checklist
- [ ] Replace
tailwind.config.tswith CSS@themeblock - [ ] Change
@tailwind base/components/utilitiesto@import "tailwindcss" - [ ] Move color definitions to
@theme { --color-*: value } - [ ] Replace
darkMode: "class"with@custom-variant dark - [ ] Move
@keyframesinside@themeblocks (ensures keyframes output with theme) - [ ] Replace
require("tailwindcss-animate")with native CSS animations - [ ] Update
h-10 w-10tosize-10(new utility) - [ ] Remove
forwardRef(React 19 passes ref as prop) - [ ] Consider OKLCH colors for better color perception
- [ ] Replace custom plugins with
@utilitydirectives
Best Practices
Do's
- Use `@theme` blocks - CSS-first configuration is v4's core pattern
- Use OKLCH colors - Better perceptual uniformity than HSL
- Compose with CVA - Type-safe variants
- Use semantic tokens -
bg-primarynotbg-blue-500 - *Use `size-
** - New shorthand forw- h-` - Add accessibility - ARIA attributes, focus states
Don'ts
- Don't use `tailwind.config.ts` - Use CSS
@themeinstead - Don't use `@tailwind` directives - Use
@import "tailwindcss" - Don't use `forwardRef` - React 19 passes ref as prop
- Don't use arbitrary values - Extend
@themeinstead - Don't hardcode colors - Use semantic tokens
- Don't forget dark mode - Test both themes
tailwind-design-system — detailed patterns and worked examples
Patterns
Pattern 1: CVA (Class Variance Authority) Components
// components/ui/button.tsx
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
const buttonVariants = cva(
// Base styles - v4 uses native CSS variables
'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: {
variant: 'default',
size: 'default',
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
}
// React 19: 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}
/>
)
}
// Usage
<Button variant="destructive" size="lg">Delete</Button>
<Button variant="outline">Cancel</Button>
<Button asChild><Link href="/home">Home</Link></Button>Pattern 2: Compound Components (React 19)
// components/ui/card.tsx
import { cn } from '@/lib/utils'
// React 19: ref is a regular prop, no forwardRef
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
}: React.HTMLAttributes<HTMLHeadingElement> & { ref?: React.Ref<HTMLHeadingElement> }) {
return (
<h3
ref={ref}
className={cn('text-2xl font-semibold leading-none tracking-tight', className)}
{...props}
/>
)
}
export function CardDescription({
className,
ref,
...props
}: React.HTMLAttributes<HTMLParagraphElement> & { ref?: React.Ref<HTMLParagraphElement> }) {
return (
<p
ref={ref}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
)
}
export function CardContent({
className,
ref,
...props
}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) {
return (
<div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
)
}
export function CardFooter({
className,
ref,
...props
}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) {
return (
<div
ref={ref}
className={cn('flex items-center p-6 pt-0', className)}
{...props}
/>
)
}
// Usage
<Card>
<CardHeader>
<CardTitle>Account</CardTitle>
<CardDescription>Manage your account settings</CardDescription>
</CardHeader>
<CardContent>
<form>...</form>
</CardContent>
<CardFooter>
<Button>Save</Button>
</CardFooter>
</Card>Pattern 3: Form Components
// components/ui/input.tsx
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 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
error && 'border-destructive focus-visible:ring-destructive',
className
)}
ref={ref}
aria-invalid={!!error}
aria-describedby={error ? `${props.id}-error` : undefined}
{...props}
/>
{error && (
<p
id={`${props.id}-error`}
className="mt-1 text-sm text-destructive"
role="alert"
>
{error}
</p>
)}
</div>
)
}
// components/ui/label.tsx
import { cva, type VariantProps } from 'class-variance-authority'
const labelVariants = cva(
'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
)
export function Label({
className,
ref,
...props
}: React.LabelHTMLAttributes<HTMLLabelElement> & { ref?: React.Ref<HTMLLabelElement> }) {
return (
<label ref={ref} className={cn(labelVariants(), className)} {...props} />
)
}
// Usage with React Hook Form + Zod
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
const schema = z.object({
email: z.string().email('Invalid email address'),
password: z.string().min(8, 'Password must be at least 8 characters'),
})
function LoginForm() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
})
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
{...register('email')}
error={errors.email?.message}
/>
</div>
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
<Input
id="password"
type="password"
{...register('password')}
error={errors.password?.message}
/>
</div>
<Button type="submit" className="w-full">Sign In</Button>
</form>
)
}Pattern 4: Responsive Grid System
// components/ui/grid.tsx
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 function Grid({ className, cols, gap, ...props }: GridProps) {
return (
<div className={cn(gridVariants({ cols, gap, className }))} {...props} />
)
}
// Container component
const containerVariants = cva('mx-auto w-full px-4 sm:px-6 lg:px-8', {
variants: {
size: {
sm: 'max-w-screen-sm',
md: 'max-w-screen-md',
lg: 'max-w-screen-lg',
xl: 'max-w-screen-xl',
'2xl': 'max-w-screen-2xl',
full: 'max-w-full',
},
},
defaultVariants: {
size: 'xl',
},
})
interface ContainerProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof containerVariants> {}
export function Container({ className, size, ...props }: ContainerProps) {
return (
<div className={cn(containerVariants({ size, className }))} {...props} />
)
}
// Usage
<Container>
<Grid cols={4} gap="lg">
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</Grid>
</Container>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-discretetransitions, and a fullDialogContent/DialogOverlayimplementation using Radix UI - Pattern 6: Dark Mode —
ThemeProvidercontext withlocalStoragepersistence,prefers-color-schemedetection, metatheme-colorupdate, and aThemeTogglebutton component
Utility Functions
// lib/utils.ts
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
// Focus ring utility
export const focusRing = cn(
"focus-visible:outline-none focus-visible:ring-2",
"focus-visible:ring-ring focus-visible:ring-offset-2",
);
// Disabled utility
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
Related skills
How it compares
Use tailwind-design-system for code-native Tailwind v4 systems; use design-md for Stitch AI screen consistency files.
FAQ
Which Tailwind version does tailwind-design-system target?
tailwind-design-system targets Tailwind CSS v4 (2024+) with CSS-first configuration. Projects on Tailwind v3 should consult the official Tailwind upgrade guide before applying this skill's patterns.
What outputs does tailwind-design-system produce?
tailwind-design-system produces design token definitions, component variant conventions, responsive utility patterns, and accessible component scaffolding for Tailwind v4 codebases building shared UI libraries.
When should developers use tailwind-design-system?
Developers use tailwind-design-system when creating component libraries, implementing shared design systems, or standardizing UI patterns with Tailwind v4 tokens, variants, and accessibility requirements.
Is Tailwind Design System safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.