Building Design Systems with CSS Variables

    Lesson 26 โ€ข Advanced Track

    What You'll Learn

    Create design tokens for colors, spacing, typography, and radii
    Build reusable component classes using only CSS custom properties
    Implement multi-theme switching (light/dark/custom) with data attributes
    Organize tokens into a scalable naming convention
    Understand the difference between semantic and primitive tokens
    Design a consistent spacing scale to eliminate magic numbers

    ๐Ÿ’ก Think of It Like This

    A design system is like a LEGO set โ€” each brick (token) has a specific size, color, and shape. Instead of sculpting every element from scratch, you assemble consistent UIs by snapping tokens together. Changing a token is like swapping the color of a LEGO brick: every structure using it updates at once.

    Understanding Design Systems

    A design system is a collection of reusable decisions โ€” colors, spacing, typography, component patterns โ€” encoded as CSS custom properties (also called "design tokens"). Instead of scattering #1976D2 across 50 files, you define it once as --color-primary and reference it everywhere.

    This approach has three major benefits: consistency (every button uses the same blue), maintainability (change the blue once, everything updates), and theming (swap all tokens at once for dark mode or branding).

    Design tokens are organized in layers. Primitive tokens are raw values like --blue-500: #1976D2. Semantic tokens give them meaning: --color-primary: var(--blue-500). Component tokens scope to specific elements: --btn-bg: var(--color-primary). This layering makes large codebases manageable.

    Token Naming Convention

    LayerExamplePurposeWhen to Use
    Primitive--blue-500Raw color valueNever directly in components
    Semantic--color-primaryRole-based referenceIn most CSS rules
    Component--btn-bgScoped to a componentFor complex component variants
    Spacing--space-4Consistent whitespaceAll padding, margin, gap values

    Step 1: Define Your Tokens

    Start by defining all your visual decisions in :root. This includes colors, spacing, typography, and border radii. The editor below shows a complete token set with a visual swatch grid.

    Design Tokens in Action

    Try it Yourself ยป
    Code Preview
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            :root {
                --color-primary: #1976D2;
                --color-primary-light: #BBDEFB;
                --color-primary-dark: #0D47A1;
                --color-success: #2E7D32;
                --color-danger: #C62828;
                --color-text: #212121;
                --color-text-muted: #757575;
                --color-bg: #FAFAFA;
                --color-surface: #FFFFFF;
    
                --space-xs: 4px;
                --space-sm: 8px;
                --space-md: 16px;
          
    ...

    Step 2: Build Components with Tokens

    Once tokens are defined, every component references them instead of hardcoded values. Notice how .btn-primary uses var(--color-primary) and .card uses var(--color-surface). If you change --color-primary from blue to purple, every button and accent updates automatically.

    Reusable Components

    Try it Yourself ยป
    Code Preview
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            :root {
                --color-primary: #1976D2;
                --color-primary-hover: #1565C0;
                --color-surface: #FFFFFF;
                --color-text: #212121;
                --color-text-muted: #757575;
                --color-border: #E0E0E0;
                --space-sm: 8px;
                --space-md: 16px;
                --space-lg: 24px;
                --radius-md: 8px;
                --font-body: system-ui, sans-serif;
            }
    
            body { font-family: var
    ...

    Step 3: Establish a Spacing Scale

    A spacing scale eliminates "magic numbers" โ€” those arbitrary pixel values like padding: 13px that creep into CSS. Instead, every spacing value comes from a predefined scale (4, 8, 12, 16, 24, 32, 48, 64px). This creates visual rhythm and makes your layouts feel cohesive.

    Spacing Scale System

    Try it Yourself ยป
    Code Preview
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            :root {
                --space-1: 4px;
                --space-2: 8px;
                --space-3: 12px;
                --space-4: 16px;
                --space-5: 20px;
                --space-6: 24px;
                --space-8: 32px;
                --space-10: 40px;
                --space-12: 48px;
                --space-16: 64px;
    
                --color-primary: #1976D2;
                --color-surface: #fff;
                --color-border: #e0e0e0;
                --color-text: #212121;
         
    ...

    Step 4: Add Theme Switching

    The ultimate payoff of a token-based system is effortless theming. By overriding tokens inside a [data-theme] attribute selector, you can switch every color in your UI with a single attribute change. No class toggling, no JavaScript manipulation of individual elements โ€” just change the data attribute and the cascade does the rest.

    Theme Switching

    Try it Yourself ยป
    Code Preview
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            :root {
                --bg: #FFFFFF;
                --text: #1a1a2e;
                --primary: #0f3460;
                --accent: #e94560;
                --surface: #f0f0f0;
            }
    
            [data-theme="dark"] {
                --bg: #1a1a2e;
                --text: #e0e0e0;
                --primary: #4fc3f7;
                --accent: #ff6b6b;
                --surface: #16213e;
            }
    
            [data-theme="forest"] {
                --bg: #f1f8e9;
                --text: #1b5e20;
    
    ...

    When to Use Design Systems

    • Any project with more than one page โ€” Even small sites benefit from centralized tokens for consistency.
    • Team projects โ€” Tokens are a shared vocabulary that prevents "which blue?" conversations.
    • Products with theming needs โ€” Dark mode, white-label branding, or seasonal themes become trivial.
    • Not needed for: One-off prototypes or single-page experiments where speed matters more than maintainability.

    โš ๏ธ Common Mistakes

    • Too many tokens too early โ€” Start with 10โ€“15 core tokens. Add more only when you notice repetition across 3+ places.
    • Using raw values in components โ€” Always reference tokens: color: var(--color-primary), never color: #1976D2.
    • Forgetting fallbacks โ€” var(--color-primary, blue) prevents breakage if a token is missing.
    • Inconsistent naming โ€” Pick one convention and stick with it. Don't mix --clr-primary and --color-main.
    • Skipping the spacing scale โ€” Without it, every developer invents their own padding values, creating visual inconsistency.
    • Not documenting tokens โ€” Create a reference page (like the swatch grid above) so the team knows what's available.

    ๐ŸŽ‰ Lesson Complete

    • โœ… Design tokens centralize all visual decisions in :root
    • โœ… Primitive โ†’ Semantic โ†’ Component is the standard token layering
    • โœ… A spacing scale (4, 8, 16, 24, 32โ€ฆ) eliminates magic numbers
    • โœ… Components use only tokens, making themes a simple override
    • โœ… [data-theme] attribute enables instant multi-theme switching
    • โœ… Start small: 10-15 tokens cover most projects initially
    • โœ… Always provide fallback values with var(--token, fallback)
    • โœ… Document your tokens visually so the team has a shared reference

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy Policy โ€ข Terms of Service