home / skills / openclaw / skills / design-system-patterns
This skill helps you implement scalable design systems by guiding token hierarchies, theming, and multi-brand patterns across platforms.
npx playbooks add skill openclaw/skills --skill design-system-patternsReview the files below or copy the command above to add this skill to your agents.
---
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
- Defining token architecture (primitive → semantic → component layers)
- Implementing light/dark/system theme switching with React
- Setting up Style Dictionary or Figma-to-code token pipelines
- Building multi-brand theming systems
- Establishing token naming conventions and governance
- Preventing flash of unstyled content (FOUC) in SSR
---
## Pattern 1: Token Hierarchy
Three-layer token architecture separates raw values from meaning from usage.
```css
/* 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.
```tsx
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<Theme>(() =>
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 <ThemeContext.Provider value={{ theme, resolvedTheme, setTheme }}>
{children}
</ThemeContext.Provider>;
}
```
Full implementation with `toggleTheme`, `disableTransitionOnChange`, and testing patterns in [references/theming-architecture.md](references/theming-architecture.md).
### Preventing FOUC in SSR (Next.js)
Inline script in `<head>` runs before paint:
```tsx
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
<html lang="en" suppressHydrationWarning>
<head>
<script dangerouslySetInnerHTML={{ __html: themeScript }} />
</head>
<body><ThemeProvider>{children}</ThemeProvider></body>
</html>
```
---
## Pattern 3: Multi-Brand Theming
Layer brand tokens on top of semantic tokens for white-label products:
```css
[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:
```javascript
// 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](references/design-tokens.md) for token category definitions, custom transforms, and platform-specific output examples.
---
## Pattern 5: Accessibility Tokens
```css
@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).
```json
{
"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
- **Token sprawl** — too many tokens without clear hierarchy
- **Inconsistent naming** — mixing camelCase and kebab-case
- **Hardcoded values** — using raw hex/rem instead of token references
- **Circular references** — tokens referencing each other in loops
- **Platform gaps** — tokens defined for web but missing for mobile
- **Missing dark mode** — semantic tokens that don't adapt to themes
---
## Related Skills
- [design-system-components](../design-system-components/) — CVA variant patterns and Surface primitives
- [distinctive-design-systems](../distinctive-design-systems/) — Aesthetic documentation and visual identity
- [theme-factory](../theme-factory/) — Pre-built theme palettes for artifacts
---
## References
- [references/design-tokens.md](references/design-tokens.md) — Complete token category definitions
- [references/theming-architecture.md](references/theming-architecture.md) — Detailed theming implementation
- [references/component-architecture.md](references/component-architecture.md) — Compound, polymorphic, and headless patterns
This skill provides foundational design system architecture focused on token hierarchies, theming infrastructure, token pipelines, and governance. It captures practical patterns for creating semantic tokens, enabling theme switching, preventing FOUC in SSR, and supporting multi-brand theming. The guidance is implementation-oriented and platform-agnostic so teams can apply it across web and mobile.
I describe a three-layer token hierarchy (primitive → semantic → component) so values are authored once and mapped to usage. I show how to implement theme providers that resolve user, system, and persisted preferences, including an inline SSR script to avoid FOUC. I also cover Style Dictionary pipelines for multi-platform token generation, brand layering, accessibility token rules, naming conventions, and a governance workflow for safe token changes.
What is the most important token layer?
Semantic tokens are most important because they express intent and enable theme switching without changing component code.
How do I prevent FOUC when server rendering?
Run a small inline script in the document head that reads persisted theme, checks system preference, and sets a theme attribute and color-scheme before paint.