Design System Patterns
Seth HobsonCommunityCreated by Seth Hobson
- Skill
- Guidelines
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a comprehensive framework for building and maintaining scalable design systems. It covers the essential architecture required to bridge the gap between design and development, focusing on token hierarchies, robust theming infrastructure, and flexible component patterns. By establishing a single source of truth, teams can ensure consistency across web and mobile applications while maintaining the ability to evolve their UI foundations.
What it does
- Defines hierarchical design token structures (primitive, semantic, component).
- Provides patterns for multi-brand and light/dark mode theming.
- Outlines advanced component architecture like compound and polymorphic patterns.
- Offers guidance on token pipelines and Figma-to-code synchronization.
- Establishes best practices for documentation and versioning of design systems.
When to use it
- When establishing the foundational visual language for a new application.
- When refactoring inconsistent UI styles into a centralized design system.
- When implementing complex theming requirements like dark mode or multi-brand support.
- When building a reusable component library that needs to scale across multiple teams.
- When automating the synchronization of design decisions from Figma to code.
Advantages
- Ensures visual consistency across large-scale applications.
- Reduces maintenance overhead through semantic token naming.
- Enables flexible component composition via headless and compound patterns.
- Supports seamless theme switching and system preference adaptation.
- Facilitates better collaboration between designers and developers.
Usage examples
- “How should I structure my design tokens to support both light and dark modes?”
- The agent provides a hierarchical approach using primitive tokens for raw values and semantic tokens that reference those primitives, demonstrating how to swap them based on theme context.
- “Explain the compound component pattern for an accordion.”
- The agent generates a React example using context to share state between an Accordion root, Item, Trigger, and Content components, ensuring a flexible and accessible API.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/wshobson/design-system-patterns/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip design-system-patterns.zip -d .agents/skills
Documentation by Seth Hobson
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
// 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)",
},
},
};Detailed patterns and worked examples
Detailed pattern documentation lives in references/details.md. Read that file when the navigation tier above is insufficient.
Best Practices
Name Tokens by Purpose: Use semantic names (text-primary) not visual descriptions (dark-gray)
Maintain Token Hierarchy: Primitives > Semantic > Component tokens
Document Token Usage: Include usage guidelines with token definitions
Version Tokens: Treat token changes as API changes with semver
Test Theme Combinations: Verify all themes work with all components
Automate Token Pipeline: CI/CD for Figma-to-code synchronization
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)
Files
- ATTRIBUTION.mdAdded by AutoGineer984 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md3.9 KiB
- references/component-architecture.md14.9 KiB
- references/design-tokens.md11.0 KiB
- references/details.md5.4 KiB
- references/theming-architecture.md12.1 KiB
references/theming-architecture.md
Theming Architecture
Overview
A robust theming system enables applications to support multiple visual appearances (light/dark modes, brand themes) while maintaining consistency and developer experience.
CSS Custom Properties Architecture
Base Setup
/* 1. Define the token contract */
:root {
/* Color scheme */
color-scheme: light dark;
/* Base tokens that don't change */
--font-sans: Inter, system-ui, sans-serif;
--font-mono: "JetBrains Mono", monospace;
/* Animation tokens */
--duration-fast: 150ms;
--duration-normal: 250ms;
--duration-slow: 400ms;
--ease-default: cubic-bezier(0.4, 0, 0.2, 1);
/* Z-index scale */
--z-dropdown: 100;
--z-sticky: 200;
--z-modal: 300;
--z-popover: 400;
--z-tooltip: 500;
}
/* 2. Light theme (default) */
:root,
[data-theme="light"] {
--color-bg: #ffffff;
--color-bg-subtle: #f8fafc;
--color-bg-muted: #f1f5f9;
--color-bg-emphasis: #0f172a;
--color-text: #0f172a;
--color-text-muted: #475569;
--color-text-subtle: #94a3b8;
--color-border: #e2e8f0;
--color-border-muted: #f1f5f9;
--color-accent: #3b82f6;
--color-accent-hover: #2563eb;
--color-accent-muted: #dbeafe;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
}
/* 3. Dark theme */
[data-theme="dark"] {
--color-bg: #0f172a;
--color-bg-subtle: #1e293b;
--color-bg-muted: #334155;
--color-bg-emphasis: #f8fafc;
--color-text: #f8fafc;
--color-text-muted: #94a3b8;
--color-text-subtle: #64748b;
--color-border: #334155;
--color-border-muted: #1e293b;
--color-accent: #60a5fa;
--color-accent-hover: #93c5fd;
--color-accent-muted: #1e3a5f;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.5);
}
/* 4. System preference detection */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
/* Inherit dark theme values */
--color-bg: #0f172a;
/* ... other dark values */
}
}Using Tokens in Components
.card {
background: var(--color-bg-subtle);
border: 1px solid var(--color-border);
border-radius: 0.5rem;
box-shadow: var(--shadow-sm);
padding: 1.5rem;
}
.card-title {
color: var(--color-text);
font-family: var(--font-sans);
font-size: 1.125rem;
font-weight: 600;
}
.card-description {
color: var(--color-text-muted);
margin-top: 0.5rem;
}
.button-primary {
background: var(--color-accent);
color: white;
transition: background var(--duration-fast) var(--ease-default);
}
.button-primary:hover {
background: var(--color-accent-hover);
}React Theme Provider
Complete Implementation
// theme-provider.tsx
import * as React from "react";
type Theme = "light" | "dark" | "system";
type ResolvedTheme = "light" | "dark";
interface ThemeProviderProps {
children: React.ReactNode;
defaultTheme?: Theme;
storageKey?: string;
attribute?: "class" | "data-theme";
enableSystem?: boolean;
disableTransitionOnChange?: boolean;
}
interface ThemeProviderState {
theme: Theme;
resolvedTheme: ResolvedTheme;
setTheme: (theme: Theme) => void;
toggleTheme: () => void;
}
const ThemeProviderContext = React.createContext<
ThemeProviderState | undefined
>(undefined);
export function ThemeProvider({
children,
defaultTheme = "system",
storageKey = "theme",
attribute = "data-theme",
enableSystem = true,
disableTransitionOnChange = false,
}: ThemeProviderProps) {
const [theme, setThemeState] = React.useState<Theme>(() => {
if (typeof window === "undefined") return defaultTheme;
return (localStorage.getItem(storageKey) as Theme) || defaultTheme;
});
const [resolvedTheme, setResolvedTheme] =
React.useState<ResolvedTheme>("light");
// Get system preference
const getSystemTheme = React.useCallback((): ResolvedTheme => {
if (typeof window === "undefined") return "light";
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}, []);
// Apply theme to DOM
const applyTheme = React.useCallback(
(newTheme: ResolvedTheme) => {
const root = document.documentElement;
// Disable transitions temporarily
if (disableTransitionOnChange) {
const css = document.createElement("style");
css.appendChild(
document.createTextNode(
`*,*::before,*::after{transition:none!important}`,
),
);
document.head.appendChild(css);
// Force repaint
(() => window.getComputedStyle(document.body))();
// Remove after a tick
setTimeout(() => {
document.head.removeChild(css);
}, 1);
}
// Apply attribute
if (attribute === "class") {
root.classList.remove("light", "dark");
root.classList.add(newTheme);
} else {
root.setAttribute(attribute, newTheme);
}
// Update color-scheme for native elements
root.style.colorScheme = newTheme;
setResolvedTheme(newTheme);
},
[attribute, disableTransitionOnChange],
);
// Handle theme changes
React.useEffect(() => {
const resolved = theme === "system" ? getSystemTheme() : theme;
applyTheme(resolved);
}, [theme, applyTheme, getSystemTheme]);
// Listen for system theme changes
React.useEffect(() => {
if (!enableSystem || theme !== "system") return;
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleChange = () => {
applyTheme(getSystemTheme());
};
mediaQuery.addEventListener("change", handleChange);
return () => mediaQuery.removeEventListener("change", handleChange);
}, [theme, enableSystem, applyTheme, getSystemTheme]);
// Persist to localStorage
const setTheme = React.useCallback(
(newTheme: Theme) => {
localStorage.setItem(storageKey, newTheme);
setThemeState(newTheme);
},
[storageKey],
);
const toggleTheme = React.useCallback(() => {
setTheme(resolvedTheme === "light" ? "dark" : "light");
}, [resolvedTheme, setTheme]);
const value = React.useMemo(
() => ({
theme,
resolvedTheme,
setTheme,
toggleTheme,
}),
[theme, resolvedTheme, setTheme, toggleTheme],
);
return (
<ThemeProviderContext.Provider value={value}>
{children}
</ThemeProviderContext.Provider>
);
}
export function useTheme() {
const context = React.useContext(ThemeProviderContext);
if (context === undefined) {
throw new Error("useTheme must be used within a ThemeProvider");
}
return context;
}Theme Toggle Component
// theme-toggle.tsx
import { Moon, Sun, Monitor } from "lucide-react";
import { useTheme } from "./theme-provider";
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
return (
<div className="flex items-center gap-1 rounded-lg bg-muted p-1">
<button
onClick={() => setTheme("light")}
className={`rounded-md p-2 ${
theme === "light" ? "bg-background shadow-sm" : ""
}`}
aria-label="Light theme"
>
<Sun className="h-4 w-4" />
</button>
<button
onClick={() => setTheme("dark")}
className={`rounded-md p-2 ${
theme === "dark" ? "bg-background shadow-sm" : ""
}`}
aria-label="Dark theme"
>
<Moon className="h-4 w-4" />
</button>
<button
onClick={() => setTheme("system")}
className={`rounded-md p-2 ${
theme === "system" ? "bg-background shadow-sm" : ""
}`}
aria-label="System theme"
>
<Monitor className="h-4 w-4" />
</button>
</div>
);
}Multi-Brand Theming
Brand Token Structure
/* Brand A - Corporate Blue */
[data-brand="corporate"] {
--brand-primary: #0066cc;
--brand-primary-hover: #0052a3;
--brand-secondary: #f0f7ff;
--brand-accent: #00a3e0;
--brand-font-heading: "Helvetica Neue", sans-serif;
--brand-font-body: "Open Sans", sans-serif;
--brand-radius: 0.25rem;
--brand-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Brand B - Modern Startup */
[data-brand="startup"] {
--brand-primary: #7c3aed;
--brand-primary-hover: #6d28d9;
--brand-secondary: #faf5ff;
--brand-accent: #f472b6;
--brand-font-heading: "Poppins", sans-serif;
--brand-font-body: "Inter", sans-serif;
--brand-radius: 1rem;
--brand-shadow: 0 4px 12px rgba(124, 58, 237, 0.15);
}
/* Brand C - Minimal */
[data-brand="minimal"] {
--brand-primary: #171717;
--brand-primary-hover: #404040;
--brand-secondary: #fafafa;
--brand-accent: #171717;
--brand-font-heading: "Space Grotesk", sans-serif;
--brand-font-body: "IBM Plex Sans", sans-serif;
--brand-radius: 0;
--brand-shadow: none;
}Accessibility Considerations
Reduced Motion
@media (prefers-reduced-motion: reduce) {
:root {
--duration-fast: 0ms;
--duration-normal: 0ms;
--duration-slow: 0ms;
}
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}High Contrast Mode
@media (prefers-contrast: high) {
:root {
--color-text: #000000;
--color-text-muted: #000000;
--color-bg: #ffffff;
--color-border: #000000;
--color-accent: #0000ee;
}
[data-theme="dark"] {
--color-text: #ffffff;
--color-text-muted: #ffffff;
--color-bg: #000000;
--color-border: #ffffff;
--color-accent: #ffff00;
}
}Forced Colors
@media (forced-colors: active) {
.button {
border: 2px solid currentColor;
}
.card {
border: 1px solid CanvasText;
}
.link {
text-decoration: underline;
}
}Server-Side Rendering
Preventing Flash of Unstyled Content
// Inline script to prevent FOUC
const themeScript = `
(function() {
const theme = localStorage.getItem('theme') || 'system';
const isDark = theme === 'dark' ||
(theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
document.documentElement.style.colorScheme = isDark ? 'dark' : 'light';
})();
`;
// In Next.js layout - note: inline scripts should be properly sanitized in production
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
<script
// Only use for trusted, static content
// For dynamic content, use a sanitization library
dangerouslySetInnerHTML={{ __html: themeScript }}
/>
</head>
<body>
<ThemeProvider>{children}</ThemeProvider>
</body>
</html>
);
}Testing Themes
// theme.test.tsx
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { ThemeProvider, useTheme } from "./theme-provider";
function TestComponent() {
const { theme, setTheme, resolvedTheme } = useTheme();
return (
<div>
<span data-testid="theme">{theme}</span>
<span data-testid="resolved">{resolvedTheme}</span>
<button onClick={() => setTheme("dark")}>Set Dark</button>
</div>
);
}
describe("ThemeProvider", () => {
it("should default to system theme", () => {
render(
<ThemeProvider>
<TestComponent />
</ThemeProvider>,
);
expect(screen.getByTestId("theme")).toHaveTextContent("system");
});
it("should switch to dark theme", async () => {
const user = userEvent.setup();
render(
<ThemeProvider>
<TestComponent />
</ThemeProvider>,
);
await user.click(screen.getByText("Set Dark"));
expect(screen.getByTestId("theme")).toHaveTextContent("dark");
expect(document.documentElement).toHaveAttribute("data-theme", "dark");
});
});Resources
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Seth Hobson
- Publisher
- Seth Hobson (Community)
- Source
- wshobson/agents · plugins/ui-design/skills/design-system-patterns · commit 4bde316
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Seth Hobson or Seth Hobson.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download design-system-patterns.zip