Design System Patterns
by @wpank
Foundational design system architecture — token hierarchies, theming infrastructure, token pipelines, and governance. Use when creating design tokens, implementing theme switching, setting up Style Dictionary, or establishing multi-brand theming. Triggers on design tokens, theme provider, Style Dictionary, token pipeline, multi-brand theming, CSS custom properties architecture.
clawhub install design-system-patterns📖 About This Skill
name: design-system-patterns model: standard description: Foundational design system architecture — token hierarchies, theming infrastructure, token pipelines, and governance. Use when creating design tokens, implementing theme switching, setting up Style Dictionary, or establishing multi-brand theming. Triggers on design tokens, theme provider, Style Dictionary, token pipeline, multi-brand theming, CSS custom properties architecture.
Design System Patterns
Foundational architecture for scalable design systems: token hierarchies, theming infrastructure, token pipelines, and governance patterns.
When to Use
Pattern 1: Token Hierarchy
Three-layer token architecture separates raw values from meaning from usage.
/* Layer 1: Primitive tokens — raw values, never used directly in components */
: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;
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
}
/* Layer 2: Semantic tokens — contextual meaning, theme-aware */
:root {
--text-primary: var(--color-gray-900);
--text-secondary: var(--color-gray-600);
--surface-default: white;
--surface-elevated: var(--color-gray-50);
--border-default: var(--color-gray-200);
--interactive-primary: var(--color-blue-500);
--interactive-primary-hover: var(--color-blue-600);
}
/* Layer 3: Component tokens — specific usage, optional */
: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);
}
> Semantic tokens are the most important layer — they enable theming. Component tokens are optional and useful for complex component libraries.
Pattern 2: Theme Switching with React
Key capabilities: theme (user selection), resolvedTheme (actual light/dark), setTheme, system preference detection, localStorage persistence, DOM attribute application.
type Theme = "light" | "dark" | "system";export function ThemeProvider({ children, defaultTheme = "system", storageKey = "theme",
attribute = "data-theme" }: { children: React.ReactNode; defaultTheme?: Theme;
storageKey?: string; attribute?: "class" | "data-theme" }) {
const [theme, setThemeState] = useState(() =>
typeof window === "undefined" ? defaultTheme
: (localStorage.getItem(storageKey) as Theme) || defaultTheme);
const [resolvedTheme, setResolvedTheme] = useState<"light" | "dark">("light");
const getSystem = useCallback(() =>
matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" as const, []);
const apply = useCallback((r: "light" | "dark") => {
const root = document.documentElement;
attribute === "class"
? (root.classList.remove("light", "dark"), root.classList.add(r))
: root.setAttribute(attribute, r);
root.style.colorScheme = r;
setResolvedTheme(r);
}, [attribute]);
useEffect(() => { apply(theme === "system" ? getSystem() : theme); }, [theme, apply, getSystem]);
useEffect(() => { // Listen for system preference changes
if (theme !== "system") return;
const mq = matchMedia("(prefers-color-scheme: dark)");
const handler = () => apply(getSystem());
mq.addEventListener("change", handler);
return () => mq.removeEventListener("change", handler);
}, [theme, apply, getSystem]);
const setTheme = useCallback((t: Theme) => {
localStorage.setItem(storageKey, t); setThemeState(t);
}, [storageKey]);
return
{children}
;
}
Full implementation with toggleTheme, disableTransitionOnChange, and testing patterns in references/theming-architecture.md.
Preventing FOUC in SSR (Next.js)
Inline script in runs before paint:
const themeScript = (function(){
var t=localStorage.getItem('theme')||'system';
var d=t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme:dark)').matches);
document.documentElement.setAttribute('data-theme',d?'dark':'light');
document.documentElement.style.colorScheme=d?'dark':'light';
})();// In layout.tsx
{children}
Pattern 3: Multi-Brand Theming
Layer brand tokens on top of semantic tokens for white-label products:
[data-brand="corporate"] {
--brand-primary: #0066cc;
--brand-primary-hover: #0052a3;
--brand-font-heading: "Helvetica Neue", sans-serif;
--brand-radius: 0.25rem;
}[data-brand="startup"] {
--brand-primary: #7c3aed;
--brand-primary-hover: #6d28d9;
--brand-font-heading: "Poppins", sans-serif;
--brand-radius: 1rem;
}
/* Map brand tokens into semantic tokens */
:root {
--interactive-primary: var(--brand-primary);
--interactive-primary-hover: var(--brand-primary-hover);
}
Pattern 4: Style Dictionary Pipeline
Multi-platform token generation from a single JSON source:
// style-dictionary.config.js — generates CSS, iOS Swift, and Android XML
module.exports = {
source: ["tokens/**/*.json"],
platforms: {
css: {
transformGroup: "css", buildPath: "dist/css/",
files: [{ destination: "variables.css", format: "css/variables",
options: { outputReferences: true } }],
},
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" } } }],
},
},
};
See references/design-tokens.md for token category definitions, custom transforms, and platform-specific output examples.
Pattern 5: Accessibility Tokens
@media (prefers-reduced-motion: reduce) {
:root {
--duration-fast: 0ms;
--duration-normal: 0ms;
--duration-slow: 0ms;
}
}@media (prefers-contrast: high) {
:root {
--text-primary: #000000;
--surface-default: #ffffff;
--border-default: #000000;
--interactive-primary: #0000ee;
}
}
@media (forced-colors: active) {
.button { border: 2px solid currentColor; }
.card { border: 1px solid CanvasText; }
}
Token Naming Conventions
Format: [category]-[property]-[variant]-[state] (e.g. color-border-input-focus)
1. kebab-case — text-primary not textPrimary
2. Semantic names — danger not red
3. State suffixes — -hover, -focus, -active, -disabled
4. Scale indicators — spacing-4, font-size-lg
Token Governance
Change management: Propose → Review (design + eng) → Test (all platforms/themes) → Deprecate (with migration path) → Remove (after deprecation period).
{
"color.primary": {
"value": "{color.primitive.blue.500}",
"deprecated": true,
"deprecatedMessage": "Use semantic.accent.default instead",
"replacedBy": "semantic.accent.default"
}
}
Best Practices
1. Name tokens by purpose — semantic names, not visual descriptions 2. Maintain the hierarchy — primitives → semantic → component 3. Version tokens — treat token changes as API changes with semver 4. Test all theme combinations — every theme must work with every component 5. Automate the pipeline — CI/CD for Figma-to-code synchronization 6. Provide migration paths — deprecate gradually with clear alternatives 7. Validate contrast — automated WCAG AA/AAA checks on token pairs
Common Pitfalls
Related Skills
References
⚡ When to Use
📋 Tips & Best Practices
1. Name tokens by purpose — semantic names, not visual descriptions 2. Maintain the hierarchy — primitives → semantic → component 3. Version tokens — treat token changes as API changes with semver 4. Test all theme combinations — every theme must work with every component 5. Automate the pipeline — CI/CD for Figma-to-code synchronization 6. Provide migration paths — deprecate gradually with clear alternatives 7. Validate contrast — automated WCAG AA/AAA checks on token pairs