--- name: design-system-patterns description: Build scalable design systems with design tokens, theming infrastructure, and component architecture patterns. Use when creating design tokens, implementing theme switching, building component libraries, or establishing design system foundations. --- # Design System Patterns Master design system architecture to create consistent, maintainable, and scalable UI foundations across web and mobile applications. ## When to Use This Skill - Creating design tokens for colors, typography, spacing, and shadows - Implementing light/dark theme switching with CSS custom properties - Building multi-brand theming systems - Architecting component libraries with consistent APIs - Establishing design-to-code workflows with Figma tokens - Creating semantic token hierarchies (primitive, semantic, component) - Setting up design system documentation and guidelines ## Core Capabilities ### 1. Design Tokens - Primitive tokens (raw values: colors, sizes, fonts) - Semantic tokens (contextual meaning: text-primary, surface-elevated) - Component tokens (specific usage: button-bg, card-border) - Token naming conventions and organization - Multi-platform token generation (CSS, iOS, Android) ### 2. Theming Infrastructure - CSS custom properties architecture - Theme context providers in React - Dynamic theme switching - System preference detection (prefers-color-scheme) - Persistent theme storage - Reduced motion and high contrast modes ### 3. Component Architecture - Compound component patterns - Polymorphic components (as prop) - Variant and size systems - Slot-based composition - Headless UI patterns - Style props and responsive variants ### 4. Token Pipeline - Figma to code synchronization - Style Dictionary configuration - Token transformation and formatting - CI/CD integration for token updates ## Quick Start ```typescript // Design tokens with CSS custom properties const tokens = { colors: { // Primitive tokens gray: { 50: '#fafafa', 100: '#f5f5f5', 900: '#171717', }, blue: { 500: '#3b82f6', 600: '#2563eb', }, }, // Semantic tokens (reference primitives) semantic: { light: { 'text-primary': 'var(--color-gray-900)', 'text-secondary': 'var(--color-gray-600)', 'surface-default': 'var(--color-white)', 'surface-elevated': 'var(--color-gray-50)', 'border-default': 'var(--color-gray-200)', 'interactive-primary': 'var(--color-blue-500)', }, dark: { 'text-primary': 'var(--color-gray-50)', 'text-secondary': 'var(--color-gray-400)', 'surface-default': 'var(--color-gray-900)', 'surface-elevated': 'var(--color-gray-800)', 'border-default': 'var(--color-gray-700)', 'interactive-primary': 'var(--color-blue-400)', }, }, }; ``` ## Key Patterns ### Pattern 1: Token Hierarchy ```css /* Layer 1: Primitive tokens (raw values) */ :root { --color-blue-500: #3b82f6; --color-blue-600: #2563eb; --color-gray-50: #fafafa; --color-gray-900: #171717; --space-1: 0.25rem; --space-2: 0.5rem; --space-4: 1rem; --font-size-sm: 0.875rem; --font-size-base: 1rem; --font-size-lg: 1.125rem; --radius-sm: 0.25rem; --radius-md: 0.5rem; --radius-lg: 1rem; } /* Layer 2: Semantic tokens (meaning) */ :root { --text-primary: var(--color-gray-900); --text-secondary: var(--color-gray-600); --surface-default: white; --interactive-primary: var(--color-blue-500); --interactive-primary-hover: var(--color-blue-600); } /* Layer 3: Component tokens (specific usage) */ :root { --button-bg: var(--interactive-primary); --button-bg-hover: var(--interactive-primary-hover); --button-text: white; --button-radius: var(--radius-md); --button-padding-x: var(--space-4); --button-padding-y: var(--space-2); } ``` ### Pattern 2: Theme Switching with React ```tsx import { createContext, useContext, useEffect, useState } from 'react'; type Theme = 'light' | 'dark' | 'system'; interface ThemeContextValue { theme: Theme; resolvedTheme: 'light' | 'dark'; setTheme: (theme: Theme) => void; } const ThemeContext = createContext(null); export function ThemeProvider({ children }: { children: React.ReactNode }) { const [theme, setTheme] = useState(() => { if (typeof window !== 'undefined') { return (localStorage.getItem('theme') as Theme) || 'system'; } return 'system'; }); const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light'); useEffect(() => { const root = document.documentElement; const applyTheme = (isDark: boolean) => { root.classList.remove('light', 'dark'); root.classList.add(isDark ? 'dark' : 'light'); setResolvedTheme(isDark ? 'dark' : 'light'); }; if (theme === 'system') { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); applyTheme(mediaQuery.matches); const handler = (e: MediaQueryListEvent) => applyTheme(e.matches); mediaQuery.addEventListener('change', handler); return () => mediaQuery.removeEventListener('change', handler); } else { applyTheme(theme === 'dark'); } }, [theme]); useEffect(() => { localStorage.setItem('theme', theme); }, [theme]); return ( {children} ); } export const useTheme = () => { const context = useContext(ThemeContext); if (!context) throw new Error('useTheme must be used within ThemeProvider'); return context; }; ``` ### Pattern 3: Variant System with CVA ```tsx import { cva, type VariantProps } from 'class-variance-authority'; import { cn } from '@/lib/utils'; const buttonVariants = cva( // Base styles 'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-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-input 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: { sm: 'h-9 px-3 text-sm', md: 'h-10 px-4 text-sm', lg: 'h-11 px-8 text-base', icon: 'h-10 w-10', }, }, defaultVariants: { variant: 'default', size: 'md', }, } ); interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { asChild?: boolean; } export function Button({ className, variant, size, ...props }: ButtonProps) { return (