Master design system architecture to create consistent, maintainable, and scalable UI foundations across web and mobile applications. - Creating design tokens for colors, typography, spacing, and shadows - Implementing light/dark theme switching with CSS custom properties
// 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)", }, }, };
/* 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` 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` 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` // 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" } }, }, ], }, }, };