KS
Killer-Skills

tailwind-design-system — Categories.community

v1.0.0
GitHub

About this Skill

Perfect for Frontend Agents needing streamlined CSS-first design system configuration with Tailwind CSS v4 Projeto que fiz pra ajudar minha mãe na cantina dela com controle de caixa e cadastro de clientes

Gstxxx Gstxxx
[0]
[0]
Updated: 3/4/2026

Quality Score

Top 5%
57
Excellent
Based on code quality & docs
Installation
SYS Universal Install (Auto-Detect)
Cursor IDE Windsurf IDE VS Code IDE
> npx killer-skills add Gstxxx/Cantina/tailwind-design-system

Agent Capability Analysis

The tailwind-design-system MCP Server by Gstxxx is an open-source Categories.community integration for Claude and other AI agents, enabling seamless task automation and capability expansion.

Ideal Agent Persona

Perfect for Frontend Agents needing streamlined CSS-first design system configuration with Tailwind CSS v4

Core Value

Empowers agents to build production-ready design systems with CSS-first configuration, design tokens, component variants, responsive patterns, and accessibility using Tailwind CSS v4, enabling seamless implementation of responsive and accessible UI components

Capabilities Granted for tailwind-design-system MCP Server

Creating component libraries with Tailwind v4
Implementing design tokens and theming with CSS-first configuration
Building responsive and accessible UI patterns

! Prerequisites & Limits

  • Targets Tailwind CSS v4 (2024+)
  • Requires upgrade for v3 projects
Project
SKILL.md
21.8 KB
.cursorrules
1.2 KB
package.json
240 B
Ready
UTF-8

# Tags

[No tags]
SKILL.md
Readonly

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 Patternv4 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

css
1/* app.css - Tailwind v4 CSS-first configuration */ 2@import "tailwindcss"; 3 4/* Define your theme with @theme */ 5@theme { 6 /* Semantic color tokens using OKLCH for better color perception */ 7 --color-background: oklch(100% 0 0); 8 --color-foreground: oklch(14.5% 0.025 264); 9 10 --color-primary: oklch(14.5% 0.025 264); 11 --color-primary-foreground: oklch(98% 0.01 264); 12 13 --color-secondary: oklch(96% 0.01 264); 14 --color-secondary-foreground: oklch(14.5% 0.025 264); 15 16 --color-muted: oklch(96% 0.01 264); 17 --color-muted-foreground: oklch(46% 0.02 264); 18 19 --color-accent: oklch(96% 0.01 264); 20 --color-accent-foreground: oklch(14.5% 0.025 264); 21 22 --color-destructive: oklch(53% 0.22 27); 23 --color-destructive-foreground: oklch(98% 0.01 264); 24 25 --color-border: oklch(91% 0.01 264); 26 --color-ring: oklch(14.5% 0.025 264); 27 28 --color-card: oklch(100% 0 0); 29 --color-card-foreground: oklch(14.5% 0.025 264); 30 31 /* Ring offset for focus states */ 32 --color-ring-offset: oklch(100% 0 0); 33 34 /* Radius tokens */ 35 --radius-sm: 0.25rem; 36 --radius-md: 0.375rem; 37 --radius-lg: 0.5rem; 38 --radius-xl: 0.75rem; 39 40 /* Animation tokens - keyframes inside @theme are output when referenced by --animate-* variables */ 41 --animate-fade-in: fade-in 0.2s ease-out; 42 --animate-fade-out: fade-out 0.2s ease-in; 43 --animate-slide-in: slide-in 0.3s ease-out; 44 --animate-slide-out: slide-out 0.3s ease-in; 45 46 @keyframes fade-in { 47 from { 48 opacity: 0; 49 } 50 to { 51 opacity: 1; 52 } 53 } 54 55 @keyframes fade-out { 56 from { 57 opacity: 1; 58 } 59 to { 60 opacity: 0; 61 } 62 } 63 64 @keyframes slide-in { 65 from { 66 transform: translateY(-0.5rem); 67 opacity: 0; 68 } 69 to { 70 transform: translateY(0); 71 opacity: 1; 72 } 73 } 74 75 @keyframes slide-out { 76 from { 77 transform: translateY(0); 78 opacity: 1; 79 } 80 to { 81 transform: translateY(-0.5rem); 82 opacity: 0; 83 } 84 } 85} 86 87/* Dark mode variant - use @custom-variant for class-based dark mode */ 88@custom-variant dark (&:where(.dark, .dark *)); 89 90/* Dark mode theme overrides */ 91.dark { 92 --color-background: oklch(14.5% 0.025 264); 93 --color-foreground: oklch(98% 0.01 264); 94 95 --color-primary: oklch(98% 0.01 264); 96 --color-primary-foreground: oklch(14.5% 0.025 264); 97 98 --color-secondary: oklch(22% 0.02 264); 99 --color-secondary-foreground: oklch(98% 0.01 264); 100 101 --color-muted: oklch(22% 0.02 264); 102 --color-muted-foreground: oklch(65% 0.02 264); 103 104 --color-accent: oklch(22% 0.02 264); 105 --color-accent-foreground: oklch(98% 0.01 264); 106 107 --color-destructive: oklch(42% 0.15 27); 108 --color-destructive-foreground: oklch(98% 0.01 264); 109 110 --color-border: oklch(22% 0.02 264); 111 --color-ring: oklch(83% 0.02 264); 112 113 --color-card: oklch(14.5% 0.025 264); 114 --color-card-foreground: oklch(98% 0.01 264); 115 116 --color-ring-offset: oklch(14.5% 0.025 264); 117} 118 119/* Base styles */ 120@layer base { 121 * { 122 @apply border-border; 123 } 124 125 body { 126 @apply bg-background text-foreground antialiased; 127 } 128}

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

typescript
1// components/ui/button.tsx 2import { Slot } from '@radix-ui/react-slot' 3import { cva, type VariantProps } from 'class-variance-authority' 4import { cn } from '@/lib/utils' 5 6const buttonVariants = cva( 7 // Base styles - v4 uses native CSS variables 8 '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', 9 { 10 variants: { 11 variant: { 12 default: 'bg-primary text-primary-foreground hover:bg-primary/90', 13 destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', 14 outline: 'border border-border bg-background hover:bg-accent hover:text-accent-foreground', 15 secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', 16 ghost: 'hover:bg-accent hover:text-accent-foreground', 17 link: 'text-primary underline-offset-4 hover:underline', 18 }, 19 size: { 20 default: 'h-10 px-4 py-2', 21 sm: 'h-9 rounded-md px-3', 22 lg: 'h-11 rounded-md px-8', 23 icon: 'size-10', 24 }, 25 }, 26 defaultVariants: { 27 variant: 'default', 28 size: 'default', 29 }, 30 } 31) 32 33export interface ButtonProps 34 extends React.ButtonHTMLAttributes<HTMLButtonElement>, 35 VariantProps<typeof buttonVariants> { 36 asChild?: boolean 37} 38 39// React 19: No forwardRef needed 40export function Button({ 41 className, 42 variant, 43 size, 44 asChild = false, 45 ref, 46 ...props 47}: ButtonProps & { ref?: React.Ref<HTMLButtonElement> }) { 48 const Comp = asChild ? Slot : 'button' 49 return ( 50 <Comp 51 className={cn(buttonVariants({ variant, size, className }))} 52 ref={ref} 53 {...props} 54 /> 55 ) 56} 57 58// Usage 59<Button variant="destructive" size="lg">Delete</Button> 60<Button variant="outline">Cancel</Button> 61<Button asChild><Link href="/home">Home</Link></Button>

Pattern 2: Compound Components (React 19)

typescript
1// components/ui/card.tsx 2import { cn } from '@/lib/utils' 3 4// React 19: ref is a regular prop, no forwardRef 5export function Card({ 6 className, 7 ref, 8 ...props 9}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) { 10 return ( 11 <div 12 ref={ref} 13 className={cn( 14 'rounded-lg border border-border bg-card text-card-foreground shadow-sm', 15 className 16 )} 17 {...props} 18 /> 19 ) 20} 21 22export function CardHeader({ 23 className, 24 ref, 25 ...props 26}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) { 27 return ( 28 <div 29 ref={ref} 30 className={cn('flex flex-col space-y-1.5 p-6', className)} 31 {...props} 32 /> 33 ) 34} 35 36export function CardTitle({ 37 className, 38 ref, 39 ...props 40}: React.HTMLAttributes<HTMLHeadingElement> & { ref?: React.Ref<HTMLHeadingElement> }) { 41 return ( 42 <h3 43 ref={ref} 44 className={cn('text-2xl font-semibold leading-none tracking-tight', className)} 45 {...props} 46 /> 47 ) 48} 49 50export function CardDescription({ 51 className, 52 ref, 53 ...props 54}: React.HTMLAttributes<HTMLParagraphElement> & { ref?: React.Ref<HTMLParagraphElement> }) { 55 return ( 56 <p 57 ref={ref} 58 className={cn('text-sm text-muted-foreground', className)} 59 {...props} 60 /> 61 ) 62} 63 64export function CardContent({ 65 className, 66 ref, 67 ...props 68}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) { 69 return ( 70 <div ref={ref} className={cn('p-6 pt-0', className)} {...props} /> 71 ) 72} 73 74export function CardFooter({ 75 className, 76 ref, 77 ...props 78}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) { 79 return ( 80 <div 81 ref={ref} 82 className={cn('flex items-center p-6 pt-0', className)} 83 {...props} 84 /> 85 ) 86} 87 88// Usage 89<Card> 90 <CardHeader> 91 <CardTitle>Account</CardTitle> 92 <CardDescription>Manage your account settings</CardDescription> 93 </CardHeader> 94 <CardContent> 95 <form>...</form> 96 </CardContent> 97 <CardFooter> 98 <Button>Save</Button> 99 </CardFooter> 100</Card>

Pattern 3: Form Components

typescript
1// components/ui/input.tsx 2import { cn } from '@/lib/utils' 3 4export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> { 5 error?: string 6 ref?: React.Ref<HTMLInputElement> 7} 8 9export function Input({ className, type, error, ref, ...props }: InputProps) { 10 return ( 11 <div className="relative"> 12 <input 13 type={type} 14 className={cn( 15 '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', 16 error && 'border-destructive focus-visible:ring-destructive', 17 className 18 )} 19 ref={ref} 20 aria-invalid={!!error} 21 aria-describedby={error ? `${props.id}-error` : undefined} 22 {...props} 23 /> 24 {error && ( 25 <p 26 id={`${props.id}-error`} 27 className="mt-1 text-sm text-destructive" 28 role="alert" 29 > 30 {error} 31 </p> 32 )} 33 </div> 34 ) 35} 36 37// components/ui/label.tsx 38import { cva, type VariantProps } from 'class-variance-authority' 39 40const labelVariants = cva( 41 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70' 42) 43 44export function Label({ 45 className, 46 ref, 47 ...props 48}: React.LabelHTMLAttributes<HTMLLabelElement> & { ref?: React.Ref<HTMLLabelElement> }) { 49 return ( 50 <label ref={ref} className={cn(labelVariants(), className)} {...props} /> 51 ) 52} 53 54// Usage with React Hook Form + Zod 55import { useForm } from 'react-hook-form' 56import { zodResolver } from '@hookform/resolvers/zod' 57import { z } from 'zod' 58 59const schema = z.object({ 60 email: z.string().email('Invalid email address'), 61 password: z.string().min(8, 'Password must be at least 8 characters'), 62}) 63 64function LoginForm() { 65 const { register, handleSubmit, formState: { errors } } = useForm({ 66 resolver: zodResolver(schema), 67 }) 68 69 return ( 70 <form onSubmit={handleSubmit(onSubmit)} className="space-y-4"> 71 <div className="space-y-2"> 72 <Label htmlFor="email">Email</Label> 73 <Input 74 id="email" 75 type="email" 76 {...register('email')} 77 error={errors.email?.message} 78 /> 79 </div> 80 <div className="space-y-2"> 81 <Label htmlFor="password">Password</Label> 82 <Input 83 id="password" 84 type="password" 85 {...register('password')} 86 error={errors.password?.message} 87 /> 88 </div> 89 <Button type="submit" className="w-full">Sign In</Button> 90 </form> 91 ) 92}

Pattern 4: Responsive Grid System

typescript
1// components/ui/grid.tsx 2import { cn } from '@/lib/utils' 3import { cva, type VariantProps } from 'class-variance-authority' 4 5const gridVariants = cva('grid', { 6 variants: { 7 cols: { 8 1: 'grid-cols-1', 9 2: 'grid-cols-1 sm:grid-cols-2', 10 3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3', 11 4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4', 12 5: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-5', 13 6: 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-6', 14 }, 15 gap: { 16 none: 'gap-0', 17 sm: 'gap-2', 18 md: 'gap-4', 19 lg: 'gap-6', 20 xl: 'gap-8', 21 }, 22 }, 23 defaultVariants: { 24 cols: 3, 25 gap: 'md', 26 }, 27}) 28 29interface GridProps 30 extends React.HTMLAttributes<HTMLDivElement>, 31 VariantProps<typeof gridVariants> {} 32 33export function Grid({ className, cols, gap, ...props }: GridProps) { 34 return ( 35 <div className={cn(gridVariants({ cols, gap, className }))} {...props} /> 36 ) 37} 38 39// Container component 40const containerVariants = cva('mx-auto w-full px-4 sm:px-6 lg:px-8', { 41 variants: { 42 size: { 43 sm: 'max-w-screen-sm', 44 md: 'max-w-screen-md', 45 lg: 'max-w-screen-lg', 46 xl: 'max-w-screen-xl', 47 '2xl': 'max-w-screen-2xl', 48 full: 'max-w-full', 49 }, 50 }, 51 defaultVariants: { 52 size: 'xl', 53 }, 54}) 55 56interface ContainerProps 57 extends React.HTMLAttributes<HTMLDivElement>, 58 VariantProps<typeof containerVariants> {} 59 60export function Container({ className, size, ...props }: ContainerProps) { 61 return ( 62 <div className={cn(containerVariants({ size, className }))} {...props} /> 63 ) 64} 65 66// Usage 67<Container> 68 <Grid cols={4} gap="lg"> 69 {products.map((product) => ( 70 <ProductCard key={product.id} product={product} /> 71 ))} 72 </Grid> 73</Container>

Pattern 5: Native CSS Animations (v4)

css
1/* In your CSS file - native @starting-style for entry animations */ 2@theme { 3 --animate-dialog-in: dialog-fade-in 0.2s ease-out; 4 --animate-dialog-out: dialog-fade-out 0.15s ease-in; 5} 6 7@keyframes dialog-fade-in { 8 from { 9 opacity: 0; 10 transform: scale(0.95) translateY(-0.5rem); 11 } 12 to { 13 opacity: 1; 14 transform: scale(1) translateY(0); 15 } 16} 17 18@keyframes dialog-fade-out { 19 from { 20 opacity: 1; 21 transform: scale(1) translateY(0); 22 } 23 to { 24 opacity: 0; 25 transform: scale(0.95) translateY(-0.5rem); 26 } 27} 28 29/* Native popover animations using @starting-style */ 30[popover] { 31 transition: 32 opacity 0.2s, 33 transform 0.2s, 34 display 0.2s allow-discrete; 35 opacity: 0; 36 transform: scale(0.95); 37} 38 39[popover]:popover-open { 40 opacity: 1; 41 transform: scale(1); 42} 43 44@starting-style { 45 [popover]:popover-open { 46 opacity: 0; 47 transform: scale(0.95); 48 } 49}
typescript
1// components/ui/dialog.tsx - Using native popover API 2import * as DialogPrimitive from '@radix-ui/react-dialog' 3import { cn } from '@/lib/utils' 4 5const DialogPortal = DialogPrimitive.Portal 6 7export function DialogOverlay({ 8 className, 9 ref, 10 ...props 11}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> & { 12 ref?: React.Ref<HTMLDivElement> 13}) { 14 return ( 15 <DialogPrimitive.Overlay 16 ref={ref} 17 className={cn( 18 'fixed inset-0 z-50 bg-black/80', 19 'data-[state=open]:animate-fade-in data-[state=closed]:animate-fade-out', 20 className 21 )} 22 {...props} 23 /> 24 ) 25} 26 27export function DialogContent({ 28 className, 29 children, 30 ref, 31 ...props 32}: React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { 33 ref?: React.Ref<HTMLDivElement> 34}) { 35 return ( 36 <DialogPortal> 37 <DialogOverlay /> 38 <DialogPrimitive.Content 39 ref={ref} 40 className={cn( 41 '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', 42 'data-[state=open]:animate-dialog-in data-[state=closed]:animate-dialog-out', 43 className 44 )} 45 {...props} 46 > 47 {children} 48 </DialogPrimitive.Content> 49 </DialogPortal> 50 ) 51}

Pattern 6: Dark Mode with CSS (v4)

typescript
1// providers/ThemeProvider.tsx - Simplified for v4 2'use client' 3 4import { createContext, useContext, useEffect, useState } from 'react' 5 6type Theme = 'dark' | 'light' | 'system' 7 8interface ThemeContextType { 9 theme: Theme 10 setTheme: (theme: Theme) => void 11 resolvedTheme: 'dark' | 'light' 12} 13 14const ThemeContext = createContext<ThemeContextType | undefined>(undefined) 15 16export function ThemeProvider({ 17 children, 18 defaultTheme = 'system', 19 storageKey = 'theme', 20}: { 21 children: React.ReactNode 22 defaultTheme?: Theme 23 storageKey?: string 24}) { 25 const [theme, setTheme] = useState<Theme>(defaultTheme) 26 const [resolvedTheme, setResolvedTheme] = useState<'dark' | 'light'>('light') 27 28 useEffect(() => { 29 const stored = localStorage.getItem(storageKey) as Theme | null 30 if (stored) setTheme(stored) 31 }, [storageKey]) 32 33 useEffect(() => { 34 const root = document.documentElement 35 root.classList.remove('light', 'dark') 36 37 const resolved = theme === 'system' 38 ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') 39 : theme 40 41 root.classList.add(resolved) 42 setResolvedTheme(resolved) 43 44 // Update meta theme-color for mobile browsers 45 const metaThemeColor = document.querySelector('meta[name="theme-color"]') 46 if (metaThemeColor) { 47 metaThemeColor.setAttribute('content', resolved === 'dark' ? '#09090b' : '#ffffff') 48 } 49 }, [theme]) 50 51 return ( 52 <ThemeContext.Provider value={{ 53 theme, 54 setTheme: (newTheme) => { 55 localStorage.setItem(storageKey, newTheme) 56 setTheme(newTheme) 57 }, 58 resolvedTheme, 59 }}> 60 {children} 61 </ThemeContext.Provider> 62 ) 63} 64 65export const useTheme = () => { 66 const context = useContext(ThemeContext) 67 if (!context) throw new Error('useTheme must be used within ThemeProvider') 68 return context 69} 70 71// components/ThemeToggle.tsx 72import { Moon, Sun } from 'lucide-react' 73import { useTheme } from '@/providers/ThemeProvider' 74 75export function ThemeToggle() { 76 const { resolvedTheme, setTheme } = useTheme() 77 78 return ( 79 <Button 80 variant="ghost" 81 size="icon" 82 onClick={() => setTheme(resolvedTheme === 'dark' ? 'light' : 'dark')} 83 > 84 <Sun className="size-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" /> 85 <Moon className="absolute size-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" /> 86 <span className="sr-only">Toggle theme</span> 87 </Button> 88 ) 89}

Utility Functions

typescript
1// lib/utils.ts 2import { type ClassValue, clsx } from "clsx"; 3import { twMerge } from "tailwind-merge"; 4 5export function cn(...inputs: ClassValue[]) { 6 return twMerge(clsx(inputs)); 7} 8 9// Focus ring utility 10export const focusRing = cn( 11 "focus-visible:outline-none focus-visible:ring-2", 12 "focus-visible:ring-ring focus-visible:ring-offset-2", 13); 14 15// Disabled utility 16export const disabled = "disabled:pointer-events-none disabled:opacity-50";

Advanced v4 Patterns

Custom Utilities with @utility

Define reusable custom utilities:

css
1/* Custom utility for decorative lines */ 2@utility line-t { 3 @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; 4} 5 6/* Custom utility for text gradients */ 7@utility text-gradient { 8 @apply bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent; 9}

Theme Modifiers

css
1/* Use @theme inline when referencing other CSS variables */ 2@theme inline { 3 --font-sans: var(--font-inter), system-ui; 4} 5 6/* Use @theme static to always generate CSS variables (even when unused) */ 7@theme static { 8 --color-brand: oklch(65% 0.15 240); 9} 10 11/* Import with theme options */ 12@import "tailwindcss" theme(static);

Namespace Overrides

css
1@theme { 2 /* Clear all default colors and define your own */ 3 --color-*: initial; 4 --color-white: #fff; 5 --color-black: #000; 6 --color-primary: oklch(45% 0.2 260); 7 --color-secondary: oklch(65% 0.15 200); 8 9 /* Clear ALL defaults for a minimal setup */ 10 /* --*: initial; */ 11}

Semi-transparent Color Variants

css
1@theme { 2 /* Use color-mix() for alpha variants */ 3 --color-primary-50: color-mix(in oklab, var(--color-primary) 5%, transparent); 4 --color-primary-100: color-mix( 5 in oklab, 6 var(--color-primary) 10%, 7 transparent 8 ); 9 --color-primary-200: color-mix( 10 in oklab, 11 var(--color-primary) 20%, 12 transparent 13 ); 14}

Container Queries

css
1@theme { 2 --container-xs: 20rem; 3 --container-sm: 24rem; 4 --container-md: 28rem; 5 --container-lg: 32rem; 6}

v3 to v4 Migration Checklist

  • Replace tailwind.config.ts with CSS @theme block
  • Change @tailwind base/components/utilities to @import "tailwindcss"
  • Move color definitions to @theme { --color-*: value }
  • Replace darkMode: "class" with @custom-variant dark
  • Move @keyframes inside @theme blocks (ensures keyframes output with theme)
  • Replace require("tailwindcss-animate") with native CSS animations
  • Update h-10 w-10 to size-10 (new utility)
  • Remove forwardRef (React 19 passes ref as prop)
  • Consider OKLCH colors for better color perception
  • Replace custom plugins with @utility directives

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-primary not bg-blue-500
  • Use size-* - New shorthand for w-* h-*
  • Add accessibility - ARIA attributes, focus states

Don'ts

  • Don't use tailwind.config.ts - Use CSS @theme instead
  • Don't use @tailwind directives - Use @import "tailwindcss"
  • Don't use forwardRef - React 19 passes ref as prop
  • Don't use arbitrary values - Extend @theme instead
  • Don't hardcode colors - Use semantic tokens
  • Don't forget dark mode - Test both themes

Resources

Related Skills

Looking for an alternative to tailwind-design-system or building a Categories.community AI Agent? Explore these related open-source MCP Servers.

View All

widget-generator

Logo of f
f

widget-generator is an open-source AI agent skill for creating widget plugins that are injected into prompt feeds on prompts.chat. It supports two rendering modes: standard prompt widgets using default PromptCard styling and custom render widgets built as full React components.

149.6k
0
Design

chat-sdk

Logo of lobehub
lobehub

chat-sdk is a unified TypeScript SDK for building chat bots across multiple platforms, providing a single interface for deploying bot logic.

73.0k
0
Communication

zustand

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication

data-fetching

Logo of lobehub
lobehub

The ultimate space for work and life — to find, build, and collaborate with agent teammates that grow with you. We are taking agent harness to the next level — enabling multi-agent collaboration, effortless agent team design, and introducing agents as the unit of work interaction.

72.8k
0
Communication