design-system-patterns ยท diff
git:20260307.47a5dbc to git:20260522.be57c0b
2 added, 216 removed. Audit A to A.
---
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<ThemeContextValue | null>(null);
-
- export function ThemeProvider({ children }: { children: React.ReactNode }) {
- const [theme, setTheme] = useState<Theme>(() => {
- 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 (
- <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>
- {children}
- </ThemeContext.Provider>
- );
- }
-
- 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<HTMLButtonElement>,
- VariantProps<typeof buttonVariants> {
- asChild?: boolean;
- }
-
- export function Button({ className, variant, size, ...props }: ButtonProps) {
- return (
- <button
- className={cn(buttonVariants({ variant, size, className }))}
- {...props}
- />
- );
- }
- ```
-
- ### Pattern 4: Style Dictionary Configuration
+ ## Detailed patterns and worked examples
- ```javascript
- // style-dictionary.config.js
- module.exports = {
- source: ["tokens/**/*.json"],
- platforms: {
- css: {
- transformGroup: "css",
- buildPath: "dist/css/",
- files: [
- {
- destination: "variables.css",
- format: "css/variables",
- options: {
- outputReferences: true, // Preserve token references
- },
- },
- ],
- },
- scss: {
- transformGroup: "scss",
- buildPath: "dist/scss/",
- files: [
- {
- destination: "_variables.scss",
- format: "scss/variables",
- },
- ],
- },
- ios: {
- transformGroup: "ios-swift",
- buildPath: "dist/ios/",
- files: [
- {
- destination: "DesignTokens.swift",
- format: "ios-swift/class.swift",
- className: "DesignTokens",
- },
- ],
- },
- android: {
- transformGroup: "android",
- buildPath: "dist/android/",
- files: [
- {
- destination: "colors.xml",
- format: "android/colors",
- filter: { attributes: { category: "color" } },
- },
- ],
- },
- },
- };
- ```
+ Detailed pattern documentation lives in `references/details.md`. Read that file when the navigation tier above is insufficient.
## Best Practices
1. **Name Tokens by Purpose**: Use semantic names (text-primary) not visual descriptions (dark-gray)
2. **Maintain Token Hierarchy**: Primitives > Semantic > Component tokens
3. **Document Token Usage**: Include usage guidelines with token definitions
4. **Version Tokens**: Treat token changes as API changes with semver
5. **Test Theme Combinations**: Verify all themes work with all components
6. **Automate Token Pipeline**: CI/CD for Figma-to-code synchronization
7. **Provide Migration Paths**: Deprecate tokens gradually with clear alternatives
## Common Issues
- **Token Sprawl**: Too many tokens without clear hierarchy
- **Inconsistent Naming**: Mixed conventions (camelCase vs kebab-case)
- **Missing Dark Mode**: Tokens that don't adapt to theme changes
- **Hardcoded Values**: Using raw values instead of tokens
- **Circular References**: Tokens referencing each other in loops
- **Platform Gaps**: Tokens missing for some platforms (web but not mobile)