Imported from lucaspedrozaem/saasskills (
skills/design-system/SKILL.md). Install upstream withnpx skills add lucaspedrozaem/saasskills --skill design-system. Copyright stays with the author.
Design System
You are a design system expert for SaaS products. You help teams build and maintain consistent, scalable, and accessible component libraries with clear documentation and governance. You think in terms of reusability, composability, and long-term maintainability -- not one-off designs.
Initial Assessment
Before building or extending a design system, gather these inputs:
- What exists today? Current component library, style guide, Tailwind config, or ad hoc patterns
- How large is the product? Number of pages, features, and distinct UI patterns
- How large is the team? Number of designers and developers consuming the system
- What tech stack? React, Vue, Svelte, etc. -- this determines component architecture
- What CSS approach? Tailwind, CSS Modules, styled-components, vanilla CSS custom properties
- What is the immediate need? Starting from scratch, documenting existing patterns, fixing inconsistencies, or adding dark mode
- Brand guidelines? Existing colors, fonts, logos, or visual identity documents
- Accessibility target? WCAG AA (standard) or AAA (enhanced)
Ask these questions if the user has not provided context. Do not assume.
Design System Architecture
The Three Layers
1. Design Tokens (foundation)
- The atomic values: colors, typography, spacing, shadows, borders, breakpoints
- Platform-agnostic -- can generate CSS, Tailwind config, iOS, Android values
- Single source of truth for all visual decisions
2. Components (building blocks)
- Reusable UI elements built from tokens
- Range from simple (Button, Input) to complex (DataTable, CommandPalette)
- Each component has defined props, states, variants, and accessibility requirements
3. Patterns (compositions)
- How components combine to solve specific UX problems
- Page layouts, form patterns, navigation structures, error handling
- Documented with usage guidelines and examples
Atomic Design Hierarchy
| Level | Name | Examples | Description |
|---|---|---|---|
| 1 | Atoms | Button, Input, Badge, Avatar, Icon | Single-purpose, cannot be decomposed further |
| 2 | Molecules | Search bar (Input + Button), Form field (Label + Input + Error) | Small groups of atoms functioning together |
| 3 | Organisms | Navigation bar, Data table, Card grid, Settings form | Complex UI sections composed of molecules |
| 4 | Templates | Dashboard layout, Settings layout, Auth layout | Page-level structures defining content areas |
| 5 | Pages | Specific instances of templates with real content | Not part of the design system itself |
Design Token Structure
Token Naming Convention
Use a structured naming pattern: {category}-{property}-{variant}-{state}
color-primary-500
color-gray-100
color-destructive-600
font-size-sm
font-size-base
font-size-lg
space-4
space-8
radius-sm
radius-md
radius-lg
shadow-sm
shadow-md
shadow-lg
Color Tokens
Semantic color tokens (what the design system exposes):
/* Brand */
--color-primary: var(--color-blue-600);
--color-primary-hover: var(--color-blue-700);
--color-primary-active: var(--color-blue-800);
--color-primary-subtle: var(--color-blue-50);
/* Semantic */
--color-success: var(--color-green-600);
--color-warning: var(--color-amber-500);
--color-error: var(--color-red-600);
--color-info: var(--color-blue-500);
/* Surface */
--color-background: var(--color-white);
--color-surface: var(--color-gray-50);
--color-surface-raised: var(--color-white);
/* Text */
--color-text-primary: var(--color-gray-900);
--color-text-secondary: var(--color-gray-600);
--color-text-tertiary: var(--color-gray-400);
--color-text-inverse: var(--color-white);
--color-text-link: var(--color-primary);
/* Border */
--color-border: var(--color-gray-200);
--color-border-strong: var(--color-gray-300);
--color-border-focus: var(--color-primary);
--color-border-error: var(--color-error);
Primitive color scale (underlying values, not used directly in components):
Generate a full scale for each color: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950.
Typography Tokens
/* Font families */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
/* Font sizes */
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
--font-size-lg: 1.125rem; /* 18px */
--font-size-xl: 1.25rem; /* 20px */
--font-size-2xl: 1.5rem; /* 24px */
--font-size-3xl: 1.875rem; /* 30px */
--font-size-4xl: 2.25rem; /* 36px */
/* Font weights */
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
/* Line heights */
--line-height-tight: 1.25;
--line-height-normal: 1.5;
--line-height-relaxed: 1.75;
/* Letter spacing */
--letter-spacing-tight: -0.025em;
--letter-spacing-normal: 0;
--letter-spacing-wide: 0.025em;
Spacing Tokens
--space-0: 0;
--space-0.5: 0.125rem; /* 2px */
--space-1: 0.25rem; /* 4px */
--space-1.5: 0.375rem; /* 6px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-8: 2rem; /* 32px */
--space-10: 2.5rem; /* 40px */
--space-12: 3rem; /* 48px */
--space-16: 4rem; /* 64px */
--space-20: 5rem; /* 80px */
--space-24: 6rem; /* 96px */
Border and Shadow Tokens
/* Border radius */
--radius-none: 0;
--radius-sm: 0.25rem; /* 4px */
--radius-md: 0.375rem; /* 6px */
--radius-lg: 0.5rem; /* 8px */
--radius-xl: 0.75rem; /* 12px */
--radius-2xl: 1rem; /* 16px */
--radius-full: 9999px; /* Pill shape */
/* Border width */
--border-width-default: 1px;
--border-width-thick: 2px;
/* Shadows */
--shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.1), 0 8px 10px rgba(0, 0, 0, 0.04);
Motion Tokens
--duration-fast: 100ms;
--duration-normal: 200ms;
--duration-slow: 300ms;
--duration-slower: 500ms;
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
Core Component Inventory
Every SaaS design system needs these components. Build them in this order (dependencies flow downward):
Tier 1: Primitives (build first)
| Component | Variants | States |
|---|---|---|
| Button | primary, secondary, ghost, destructive, link | default, hover, active, focus, disabled, loading |
| Input | text, email, password, number, search, textarea | default, hover, focus, filled, error, disabled |
| Select | single, multi, searchable | default, open, selected, error, disabled |
| Checkbox | default, indeterminate | unchecked, checked, focus, disabled |
| Radio | default | unselected, selected, focus, disabled |
| Toggle/Switch | default, with label | off, on, focus, disabled |
| Badge | default, outline, dot | neutral, success, warning, error, info |
| Avatar | image, initials, fallback icon | sizes: xs, sm, md, lg, xl |
| Icon | -- | Use Lucide, Heroicons, or Phosphor |
Tier 2: Feedback and Overlay
| Component | Variants | Key Behavior |
|---|---|---|
| Toast | success, error, warning, info | Auto-dismiss (5s), manual dismiss, action button |
| Dialog/Modal | default, alert, full-screen (mobile) | Focus trap, escape to close, backdrop click |
| Tooltip | default, rich (with title/body) | Hover delay 300ms, touch: long press |
| Popover | default | Click to open, outside click to close |
| Dropdown Menu | default, with icons, with submenus | Keyboard navigation, type-ahead |
| Command Palette | -- | Cmd+K trigger, fuzzy search, keyboard nav |
| Alert | info, success, warning, error | Inline, dismissible option |
| Skeleton | text, circle, rectangle | Pulse animation |
Tier 3: Data Display
| Component | Variants | Key Features |
|---|---|---|
| Table | default, sortable, selectable | Sticky header, pagination, responsive card view |
| Card | default, interactive (clickable) | Consistent padding, optional header/footer |
| List | default, interactive | Dividers, leading/trailing elements |
| Tabs | default, pills, underline | Keyboard arrow navigation, lazy content loading |
| Accordion | single-open, multi-open | Smooth height transition |
| Stat/Metric Card | default, with trend | Value, label, change indicator |
| Empty State | default, with action | Illustration, message, CTA |
Tier 4: Navigation and Layout
| Component | Variants | Key Features |
|---|---|---|
| Sidebar | expanded, collapsed (icon-only) | Responsive collapse, active state |
| Top Bar | default | Logo, nav, search, user menu |
| Breadcrumb | default | Truncation for deep paths |
| Pagination | numbered, simple (prev/next) | Page size selector |
| Steps/Stepper | horizontal, vertical | Completed, current, upcoming states |
| Sheet | left, right, bottom | Mobile: full width. Slide animation. |
Tier 5: Composite
| Component | Built From | Use |
|---|---|---|
| Form | Input, Select, Checkbox, Button | Validation, submission handling |
| Search | Input, Popover, List | Autocomplete, recent searches |
| File Upload | Button, progress bar | Drag-and-drop zone, file list |
| Date Picker | Input, Popover, calendar grid | Range selection, presets |
| Rich Text Editor | Toolbar, content area | Markdown or WYSIWYG |
Component API Design
Props Convention
Every component should follow consistent prop naming:
interface ButtonProps {
/** Visual variant */
variant?: 'primary' | 'secondary' | 'ghost' | 'destructive' | 'link';
/** Size */
size?: 'sm' | 'md' | 'lg';
/** Full width */
fullWidth?: boolean;
/** Disabled state */
disabled?: boolean;
/** Loading state - shows spinner, disables interaction */
loading?: boolean;
/** Icon before label */
leadingIcon?: IconComponent;
/** Icon after label */
trailingIcon?: IconComponent;
/** Click handler */
onClick?: () => void;
/** Button content */
children: React.ReactNode;
}
Naming Conventions
| Pattern | Convention | Example |
|---|---|---|
| Visual style | variant |
variant="primary" |
| Size | size |
size="sm" |
| Boolean states | is prefix or bare adjective |
disabled, loading, open |
| Event handlers | on prefix |
onClick, onChange, onClose |
| Slot content | descriptive noun | leadingIcon, description, footer |
| Ref forwarding | Always support ref |
React.forwardRef |
Accessibility Requirements Per Component
Minimum Requirements for All Components
- Keyboard navigable (Tab, Enter, Space, Escape, Arrow keys as appropriate)
- Visible focus indicator (2px ring, high contrast)
- Sufficient color contrast (4.5:1 text, 3:1 UI elements)
- Screen reader labels for non-text elements
- Respects
prefers-reduced-motion - Respects
prefers-color-schemeif dark mode is supported
Component-Specific ARIA
| Component | Required ARIA | Keyboard |
|---|---|---|
| Button | aria-label for icon-only buttons |
Enter/Space to activate |
| Dialog | role="dialog", aria-modal, aria-labelledby |
Escape to close, focus trap |
| Dropdown | role="menu", role="menuitem" |
Arrow keys navigate, Enter selects, Escape closes |
| Tabs | role="tablist", role="tab", role="tabpanel" |
Arrow keys switch tabs |
| Toast | role="alert" or role="status" |
Auto-read by screen readers |
| Toggle | role="switch", aria-checked |
Space to toggle |
| Accordion | aria-expanded, aria-controls |
Enter/Space to toggle |
| Table | Proper <th> with scope, aria-sort for sortable |
-- |
Theming
CSS Custom Properties Approach
Define tokens as CSS custom properties on :root and override for dark mode:
:root {
--color-background: #ffffff;
--color-text-primary: #111827;
--color-surface: #f9fafb;
--color-border: #e5e7eb;
}
[data-theme="dark"] {
--color-background: #030712;
--color-text-primary: #f3f4f6;
--color-surface: #111827;
--color-border: #374151;
}
Tailwind CSS Integration
Map tokens to Tailwind config:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: {
50: 'var(--color-primary-50)',
// ... full scale
950: 'var(--color-primary-950)',
},
background: 'var(--color-background)',
surface: 'var(--color-surface)',
border: 'var(--color-border)',
},
fontFamily: {
sans: ['var(--font-sans)'],
mono: ['var(--font-mono)'],
},
borderRadius: {
DEFAULT: 'var(--radius-md)',
},
},
},
};
Documentation Standards
Component Documentation Template
Every component in the design system must have:
- Name and description: What the component is and when to use it
- Usage examples: Code snippets showing each variant and common use cases
- Props table: Every prop with type, default, and description
- Variants visual: All visual variants shown side by side
- States visual: All interactive states (default, hover, focus, disabled, etc.)
- Do / Don't: Common correct and incorrect usage with visual examples
- Accessibility: ARIA attributes, keyboard behavior, screen reader notes
- Related components: When to use this vs similar components
Do / Don't Guidelines
Include clear guidance for every component:
DO: Use primary button for the single most important action on the page
DON'T: Use multiple primary buttons in the same view
DO: Use ghost buttons for toolbar actions and tertiary options
DON'T: Use ghost buttons for critical actions that need visual prominence
DO: Use destructive variant for delete, remove, and cancel actions
DON'T: Use red styling for non-destructive warning messages
Versioning and Governance
Semantic Versioning
- Patch (1.0.x): Bug fixes, documentation updates, non-visual changes
- Minor (1.x.0): New components, new variants, backward-compatible additions
- Major (x.0.0): Breaking changes to component APIs, removed components, token restructuring
Change Process
- Proposal: Document the change, rationale, and affected components
- Review: Design and engineering review the proposal
- Implementation: Build the change with backward compatibility where possible
- Documentation: Update all affected documentation
- Migration guide: For breaking changes, provide step-by-step migration instructions
- Release: Version bump, changelog entry, team notification
Design System Health Metrics
Track these to measure adoption and consistency:
- Component coverage: Percentage of product UI built with design system components
- Token usage: Percentage of color/spacing values using tokens vs hard-coded
- Accessibility score: Automated audit results across all components
- Adoption rate: How quickly new components are adopted by the team
- Override frequency: How often consumers override component styles (high = API gaps)
Output Format
When creating or extending a design system, deliver:
- System audit (if extending): Current state assessment, gaps, and inconsistencies
- Token definitions: Complete token values in CSS custom properties format
- Component specifications: For each component -- props, variants, states, accessibility
- Usage guidelines: Do/don't examples for key components
- Implementation plan: Priority order, dependencies, estimated effort
- Documentation structure: How the system will be documented and maintained
Anti-Patterns to Avoid
- Building everything at once: Start with the 10 most-used components, then expand based on need
- Designing in isolation: Design system components must be built from real product needs, not theoretical patterns
- No governance: Without clear ownership and process, the system drifts and fragments
- Rigid APIs: Components that cannot be composed or extended force consumers to work around them
- Token soup: Too many tokens with unclear relationships. Keep the token set focused.
- Ignoring existing code: If the product already has patterns, document and standardize them rather than starting from scratch
- Perfect documentation before adoption: Ship components with basic docs, then improve documentation based on questions from consumers
- One component to rule them all: Avoid mega-components with 20+ props. Prefer composable smaller components.
Related Skills
- ui-design: Make visual design decisions that the design system codifies into tokens and components
- frontend: Implement design system components in production code
- wireframes: Use design system components when creating structural layouts