# Design System Theme System Guide **Version:** 1.0.0 **Last Updated:** December 7, 2025 Complete guide to theming and customizing the design system. --- ## Table of Contents 1. [Theme Overview](#theme-overview) 2. [Light Mode (Default)](#light-mode-default) 3. [Dark Mode](#dark-mode) 4. [Custom Themes](#custom-themes) 5. [Theme Switching](#theme-switching) 6. [CSS Variable Customization](#css-variable-customization) 7. [Component Theming](#component-theming) 8. [Best Practices](#best-practices) --- ## Theme Overview The design system includes: - ✅ Light mode (default) - ✅ Dark mode (CSS class-based) - ✅ Full customization via CSS variables - ✅ Per-component theme support - ✅ Automatic contrast checking ### How Theming Works Themes are implemented using CSS custom properties (variables) that automatically apply based on a class on the root element: ```html ... ... ``` --- ## Light Mode (Default) Light mode is the default theme with clean, bright colors optimized for daytime viewing. ### Color Palette (Light Mode) | Token | Color | HEX | Usage | |-------|-------|-----|-------| | `--primary` | Blue | `#3b82f6` | Primary actions, focus | | `--secondary` | Indigo | `#6366f1` | Secondary elements | | `--success` | Green | `#10b981` | Success feedback | | `--warning` | Amber | `#f59e0b` | Warning messages | | `--destructive` | Red | `#ef4444` | Error/delete actions | | `--info` | Cyan | `#0ea5e9` | Information | | `--foreground` | Slate-900 | `#0f172a` | Primary text | | `--muted-foreground` | Slate-600 | `#64748b` | Secondary text | | `--background` | White | `#ffffff` | Page background | | `--card` | Slate-50 | `#f8fafc` | Card backgrounds | | `--card-foreground` | Slate-900 | `#1e293b` | Card text | | `--border` | Slate-200 | `#e2e8f0` | Borders | | `--input` | White | `#ffffff` | Input backgrounds | | `--ring` | Blue | `#3b82f6` | Focus rings | ### Light Mode Appearance - Clear distinction between elements - High contrast text (4.5:1+) - Subtle shadows for depth - Neutral backgrounds - Vibrant accent colors ### CSS ```css :root { /* Light mode variables are set by default */ --primary: #3b82f6; --secondary: #6366f1; --success: #10b981; --warning: #f59e0b; --destructive: #ef4444; --info: #0ea5e9; --foreground: #0f172a; --muted-foreground: #64748b; --background: #ffffff; --card: #f8fafc; --card-foreground: #1e293b; --border: #e2e8f0; --input: #ffffff; --ring: #3b82f6; } ``` --- ## Dark Mode Dark mode provides eye-friendly colors for low-light environments. ### Enabling Dark Mode ```javascript // Add dark class to enable dark mode document.documentElement.classList.add('dark'); ``` ### Color Palette (Dark Mode) | Token | Color | HEX | Usage | |-------|-------|-----|-------| | `--primary` | Light Blue | `#60a5fa` | Primary actions | | `--secondary` | Light Indigo | `#818cf8` | Secondary elements | | `--success` | Light Green | `#34d399` | Success feedback | | `--warning` | Light Amber | `#fbbf24` | Warning messages | | `--destructive` | Light Red | `#f87171` | Error/delete actions | | `--info` | Light Cyan | `#38bdf8` | Information | | `--foreground` | Slate-50 | `#f1f5f9` | Primary text | | `--muted-foreground` | Slate-400 | `#cbd5e1` | Secondary text | | `--background` | Slate-950 | `#0f172a` | Page background | | `--card` | Slate-900 | `#1e293b` | Card backgrounds | | `--card-foreground` | Slate-50 | `#e2e8f0` | Card text | | `--border` | Slate-800 | `#334155` | Borders | | `--input` | Slate-900 | `#1f2937` | Input backgrounds | | `--ring` | Light Blue | `#60a5fa` | Focus rings | ### Dark Mode Appearance - Dark backgrounds reduce eye strain - Brighter text for readability - Adjusted accent colors for clarity - Softer shadows - Maintained contrast ratios ### CSS ```css :root.dark { --primary: #60a5fa; --secondary: #818cf8; --success: #34d399; --warning: #fbbf24; --destructive: #f87171; --info: #38bdf8; --foreground: #f1f5f9; --muted-foreground: #cbd5e1; --background: #0f172a; --card: #1e293b; --card-foreground: #e2e8f0; --border: #334155; --input: #1f2937; --ring: #60a5fa; } ``` ### Component Support All 9 components support dark mode: - ✅ DsButton - All variants themed - ✅ DsInput - Form fields themed - ✅ DsCard - Background and text adjusted - ✅ DsBadge - Color variants adjusted - ✅ DsToast - Backgrounds and text adjusted - ✅ DsWorkflow - Step colors adjusted - ✅ DsNotificationCenter - Scrollbar styled - ✅ DsActionBar - Background themed - ✅ DsToastProvider - Inherits from toasts --- ## Custom Themes Create custom themes by overriding CSS variables. ### Creating a Custom Theme ```css /* custom-theme.css */ :root.custom-theme { /* Custom brand colors */ --primary: #6d28d9; /* Deep purple */ --secondary: #d946ef; /* Magenta */ --success: #22c55e; /* Bright green */ --warning: #eab308; /* Bright yellow */ --destructive: #dc2626; /* Bright red */ /* Custom backgrounds */ --background: #f9f5ff; /* Lavender white */ --card: #f3e8ff; /* Light purple */ --card-foreground: #3f0f63; /* Dark purple text */ /* Custom text colors */ --foreground: #1f1337; /* Dark purple */ --muted-foreground: #6b5280; /* Muted purple */ /* Adjust other tokens as needed */ --border: #e9d5ff; /* Light purple border */ --input: #fafaf9; /* Warm white */ } ``` ### Applying Custom Theme ```html ... ``` ```javascript // Switch to custom theme document.documentElement.classList.add('custom-theme'); // Remove other themes document.documentElement.classList.remove('dark', 'light'); ``` ### Brand-Specific Theme Example ```css /* tech-brand-theme.css - Modern tech company theme */ :root.tech-brand { --primary: #0066ff; /* Vibrant blue */ --secondary: #00d4ff; /* Cyan */ --success: #00ff88; /* Neon green */ --warning: #ffaa00; /* Bright orange */ --destructive: #ff3366; /* Hot pink */ --foreground: #1a1a2e; /* Dark blue */ --background: #0f1419; /* Almost black */ --card: #161b22; /* Slightly lighter black */ --card-foreground: #ffffff; /* Pure white text */ --border: #30363d; /* Dark gray borders */ } :root.tech-brand.dark { /* Dark mode would be even more dark/vibrant */ --primary: #00d4ff; /* Swap primary/secondary in dark */ --secondary: #0066ff; --success: #00ff88; } ``` ### Corporate Theme Example ```css /* corporate-theme.css - Professional corporate theme */ :root.corporate { --primary: #003366; /* Navy blue */ --secondary: #666666; /* Gray */ --success: #006600; /* Dark green */ --warning: #cc6600; /* Brown-orange */ --destructive: #990000; /* Dark red */ --foreground: #000000; /* Pure black */ --background: #ffffff; /* Pure white */ --card: #f5f5f5; /* Light gray */ --card-foreground: #333333; /* Dark gray text */ --border: #cccccc; /* Medium gray borders */ } ``` --- ## Theme Switching ### Simple Theme Toggle ```html ``` ### Theme Switcher with Dropdown ```html ``` ### System Preference Detection ```javascript // Detect system dark mode preference function getSystemTheme() { if (window.matchMedia('(prefers-color-scheme: dark)').matches) { return 'dark'; } return 'light'; } // Apply system theme on page load function applySystemTheme() { const saved = localStorage.getItem('preferred-theme'); const theme = saved || getSystemTheme(); if (theme === 'dark') { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } } applySystemTheme(); // Listen for system theme changes window.matchMedia('(prefers-color-scheme: dark)') .addEventListener('change', (e) => { if (!localStorage.getItem('preferred-theme')) { // Only change if user hasn't set preference if (e.matches) { document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } } }); ``` ### Theme Switcher Component ```html
``` --- ## CSS Variable Customization ### Override Global Variables ```css /* Override for entire page */ :root { --primary: #your-color; --space-4: 1.25rem; --duration-normal: 0.3s; } ``` ### Override for Specific Components ```css /* Custom styling for one component */ .my-special-button { --primary: #ff6b6b; /* Use different color */ background: var(--primary); } /* Custom styling for theme */ :root.my-theme { --primary: #667eea; --secondary: #764ba2; } ``` ### Using Variables in JavaScript ```javascript // Get variable value const primaryColor = getComputedStyle(document.documentElement) .getPropertyValue('--primary') .trim(); // Set variable value document.documentElement.style.setProperty('--primary', '#ff0000'); // In component class CustomComponent extends HTMLElement { getPrimaryColor() { return getComputedStyle(this).getPropertyValue('--primary').trim(); } setPrimaryColor(color) { this.style.setProperty('--primary', color); } } ``` --- ## Component Theming ### Button Theming ```css /* Light mode button colors */ .ds-btn[data-variant="primary"] { background: var(--primary); color: white; } .ds-btn[data-variant="success"] { background: var(--success); color: white; } /* Dark mode adjustments (automatic via tokens) */ :root.dark .ds-btn[data-variant="primary"] { background: var(--primary); /* Already adjusted in tokens */ color: white; } ``` ### Input Theming ```css /* Light mode input */ .ds-input { background: var(--input); border: 2px solid var(--border); color: var(--foreground); } /* Dark mode input (automatic) */ :root.dark .ds-input { background: var(--input); /* Dark background */ border-color: var(--border); /* Lighter border */ color: var(--foreground); /* Light text */ } /* Focus state (works in both themes) */ .ds-input:focus { border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in oklch, var(--ring) 20%, transparent); } ``` ### Card Theming ```css /* Light mode card */ .ds-card { background: var(--card); color: var(--card-foreground); border: 1px solid var(--border); } /* Dark mode card (automatic) */ :root.dark .ds-card { background: var(--card); /* Dark background */ color: var(--card-foreground); /* Light text */ border-color: var(--border); /* Darker border */ } ``` ### Toast Theming ```css /* Light mode toast */ .ds-toast[data-type="success"] { border-left: 4px solid var(--success); background: linear-gradient(135deg, color-mix(in oklch, var(--success) 5%, var(--card)) 0%, var(--card) 100%); } /* Dark mode toast (automatic) */ :root.dark .ds-toast[data-type="success"] { /* Uses dark theme tokens automatically */ border-left-color: var(--success); background: linear-gradient(135deg, color-mix(in oklch, var(--success) 5%, var(--card)) 0%, var(--card) 100%); } ``` --- ## Best Practices ### 1. Always Use Tokens ```css /* ✅ Good */ .my-button { background: var(--primary); color: var(--foreground); padding: var(--space-4); } /* ❌ Bad */ .my-button { background: #3b82f6; color: #0f172a; padding: 16px; } ``` ### 2. Test in Both Themes ```javascript // Test dark mode document.documentElement.classList.add('dark'); // Check colors, contrast, visibility // Test light mode document.documentElement.classList.remove('dark'); // Check colors, contrast, visibility ``` ### 3. Maintain Contrast Ensure all text meets WCAG 2.1 AA minimum (4.5:1 contrast ratio): ```javascript // Validate contrast function checkContrast(foreground, background) { const fgLum = getRelativeLuminance(foreground); const bgLum = getRelativeLuminance(background); const ratio = (Math.max(fgLum, bgLum) + 0.05) / (Math.min(fgLum, bgLum) + 0.05); return ratio >= 4.5; // WCAG AA } ``` ### 4. Respect User Preferences ```javascript // Always check prefers-color-scheme if (window.matchMedia('(prefers-color-scheme: dark)').matches) { // Apply dark mode } else { // Apply light mode } // Listen for changes window.matchMedia('(prefers-color-scheme: dark)') .addEventListener('change', (e) => { // Update theme }); ``` ### 5. Announce Theme Changes ```javascript // Emit custom event when theme changes const event = new CustomEvent('theme-change', { detail: { theme: isDark ? 'dark' : 'light' } }); document.dispatchEvent(event); // Listen for theme changes document.addEventListener('theme-change', (e) => { console.log('Theme changed to:', e.detail.theme); }); ``` ### 6. Handle Transitions Smoothly ```css /* Smooth color transitions when switching themes */ * { transition: background-color 0.2s ease, color 0.2s ease; } /* But avoid transitions on initial load */ *:not(:root):not(body) { transition: none; } :root.theme-changing * { transition: background-color 0.2s ease, color 0.2s ease; } ``` ### 7. Document Custom Themes ```markdown # Custom Theme: TechBrand ## Colors - Primary: #0066ff (Vibrant Blue) - Secondary: #00d4ff (Cyan) - Success: #00ff88 (Neon Green) ## Usage ```html ``` ## Dark Mode Automatically supports dark theme with enhanced contrast. ``` --- ## Troubleshooting ### Issue: Theme not applying **Solution:** Make sure CSS is loaded before HTML: ```javascript // Load in this order: import '@company/design-system/css/variants.css'; import '@company/design-system/css/components.css'; ``` ### Issue: Custom colors not working **Solution:** Use CSS custom properties, not hardcoded values: ```css /* ✅ Works */ --primary: #your-color; /* ❌ Doesn't work */ background: #your-color; ``` ### Issue: Dark mode colors don't match **Solution:** Adjust tokens in dark mode CSS: ```css :root.dark { --primary: #lighter-color; /* Use lighter shade in dark mode */ } ``` ### Issue: Contrast is too low **Solution:** Check WCAG ratios and adjust colors: ```javascript // Aim for 4.5:1 minimum (WCAG AA) // 7:1+ for best accessibility (WCAG AAA) ``` --- ## Summary The design system theming system provides: ✅ **Light & Dark modes** - Out of the box ✅ **42 CSS variables** - Full customization ✅ **Automatic component support** - All 9 components themed ✅ **High contrast** - WCAG 2.1 AA compliant ✅ **System preference detection** - Respects OS preference ✅ **Persistence** - Save user theme preference ✅ **Custom themes** - Create brand-specific themes ✅ **Smooth transitions** - Animate theme changes --- **For more help:** design-system@company.com