Lesson 12: Component-Based Design & Maintainable CSS

Learning Outcomes

After this lesson, you will understand how to organize CSS for large, maintainable projects using component-based design principles. You will master BEM naming conventions for creating self-documenting CSS, use CSS custom properties to build flexible design systems with design tokens, and create reusable component libraries for buttons, cards, and forms. You will learn CSS architecture patterns for scaling projects, implement theme systems including dark mode, and understand how component thinking prepares you for modern frameworks like React and Vue.

Prerequisites

You should be comfortable with all basic CSS concepts from Lessons 03-05, including selectors, specificity, the box model, and layout techniques. Understanding advanced layout from Lesson 11 will help you see how components fit into larger page structures.

Why Component-Based Design Matters

As projects grow from simple pages to complex applications, CSS becomes increasingly difficult to maintain without organization. Styles conflict, specificity wars emerge, and making changes becomes risky because you can't predict what else might break. Component-based design solves these problems by treating UI elements as independent, reusable building blocks.

Component thinking means designing each UI element—buttons, cards, navigation bars, forms—as a self-contained unit with its own styles that don't leak to or from other elements. This mirrors how modern JavaScript frameworks work and prepares you for professional development.

Benefits of component-based CSS:

Component Thinking and Single Responsibility

The single responsibility principle states that each component should do one thing and do it well. A button component handles button styling and behavior. A card component creates a container for grouped content. A navigation component manages site navigation. Each focuses on its specific purpose.

Identifying Components

Look at any web page and you'll see repeating patterns that are candidates for components:

Each of these patterns appears multiple times across a site. Creating components means writing the CSS once and applying it consistently everywhere that pattern appears.

Component Independence

A well-designed component works correctly regardless of where it appears on the page. It doesn't depend on parent containers having specific classes or rely on global styles beyond a base theme. This independence means you can drop a button component into any page and it looks and works as expected.

BEM Methodology: Block Element Modifier

BEM (Block Element Modifier) is a naming convention that makes CSS self-documenting and prevents style conflicts. It uses specific naming patterns to show the relationship between HTML elements and their styles at a glance.

BEM Structure

BEM names consist of three parts connected with specific delimiters:

BEM in Practice

Example: Card component with BEM

<!-- The Block -->
<div class="card">
    <!-- Elements of the card block -->
    <img src="photo.jpg" alt="Photo" class="card__image">
    <div class="card__content">
        <h3 class="card__title">Article Title</h3>
        <p class="card__description">Article summary goes here</p>
        <button class="card__button">Read More</button>
    </div>
</div>

<!-- Same block with a modifier -->
<div class="card card--featured">
    <!-- Featured card looks different but uses same structure -->
    <img src="photo.jpg" alt="Photo" class="card__image">
    <div class="card__content">
        <h3 class="card__title">Featured Article</h3>
        <p class="card__description">This card is highlighted</p>
        <button class="card__button card__button--large">Read More</button>
    </div>
</div>

CSS for the BEM card component:

/* Block: The card component */
.card {
    background: white;
    border-radius: 0.5rem;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    overflow: hidden;
}

/* Element: Parts of the card */
.card__image {
    width: 100%;
    height: 200px;
    object-fit: cover;
}

.card__content {
    padding: 1.5rem;
}

.card__title {
    font-size: 1.5rem;
    margin-bottom: 0.5rem;
    color: #1f2937;
}

.card__description {
    color: #6b7280;
    margin-bottom: 1rem;
}

.card__button {
    padding: 0.5rem 1rem;
    background: #2563eb;
    color: white;
    border: none;
    border-radius: 0.25rem;
    cursor: pointer;
}

/* Modifier: Featured variant */
.card--featured {
    border: 2px solid #2563eb;
    box-shadow: 0 8px 16px rgba(37, 99, 235, 0.2);
}

.card--featured .card__title {
    color: #2563eb;
}

/* Modifier on element: Large button variant */
.card__button--large {
    padding: 0.75rem 1.5rem;
    font-size: 1.125rem;
}

BEM Benefits

BEM Rules and Best Practices

Keep element names flat: Never nest element names like card__content__title. Use card__title even if it's inside card__content. This keeps names concise and avoids deep nesting complexity.

Modifiers extend, not replace: Always include the base class with a modifier: class="button button--large", not just class="button--large". The modifier adds to the base styles.

Avoid tag selectors in components: Use .card__title instead of .card h3. This makes components more flexible and prevents specificity issues.

CSS Custom Properties (Variables)

CSS custom properties (also called CSS variables) let you store values and reuse them throughout your stylesheet. They enable theming, reduce repetition, and make global changes effortless. Unlike Sass variables which are compiled away, CSS variables are live in the browser and can be changed with JavaScript.

Declaring and Using Variables

Example: Basic CSS variables

:root {
    /* Declare variables on :root to make them global */
    --primary-color: #2563eb;
    --secondary-color: #10b981;
    --text-color: #1f2937;
    --text-light: #6b7280;
    --spacing-sm: 0.5rem;
    --spacing-md: 1rem;
    --spacing-lg: 1.5rem;
    --border-radius: 0.5rem;
}

/* Use variables with var() function */
.button {
    background: var(--primary-color);
    color: white;
    padding: var(--spacing-md) var(--spacing-lg);
    border-radius: var(--border-radius);
}

.card {
    border-radius: var(--border-radius);
    padding: var(--spacing-lg);
}

.heading {
    color: var(--text-color);
    margin-bottom: var(--spacing-md);
}

Fallback Values

The var() function accepts a fallback value as a second argument, used if the variable isn't defined:

.element {
    /* If --primary-color isn't defined, use #2563eb */
    background: var(--primary-color, #2563eb);

    /* Fallback can also be another variable */
    color: var(--text-color, var(--fallback-color, black));
}

Scoped Variables

Variables can be scoped to specific elements and their descendants, allowing component-specific overrides:

:root {
    --button-bg: #2563eb;
}

.button {
    background: var(--button-bg);
}

/* Alert buttons get a different color */
.alert--error {
    --button-bg: #dc2626;  /* Red for error alerts */
}

.alert--success {
    --button-bg: #10b981;  /* Green for success alerts */
}
/* Any button inside .alert--error automatically uses red */

Calculated Values

CSS variables work with calc() for dynamic calculations:

:root {
    --spacing-unit: 0.5rem;
}

.small-margin {
    margin: var(--spacing-unit);  /* 0.5rem */
}

.medium-margin {
    margin: calc(var(--spacing-unit) * 2);  /* 1rem */
}

.large-margin {
    margin: calc(var(--spacing-unit) * 4);  /* 2rem */
}

Design Tokens and Design Systems

Design tokens are the variables that define your design system—colors, typography, spacing, shadows, borders, and other visual properties. Organizing these as CSS variables creates a single source of truth for your design decisions.

Building a Token System

Example: Complete design token system

:root {
    /* ========================================
       COLOR TOKENS
       ======================================== */

    /* Primary palette */
    --color-primary-50: #eff6ff;
    --color-primary-100: #dbeafe;
    --color-primary-200: #bfdbfe;
    --color-primary-300: #93c5fd;
    --color-primary-400: #60a5fa;
    --color-primary-500: #3b82f6;  /* Main primary */
    --color-primary-600: #2563eb;
    --color-primary-700: #1d4ed8;
    --color-primary-800: #1e40af;
    --color-primary-900: #1e3a8a;

    /* Semantic colors (built from palette) */
    --color-primary: var(--color-primary-600);
    --color-primary-hover: var(--color-primary-700);
    --color-primary-light: var(--color-primary-100);

    /* Neutral palette */
    --color-gray-50: #f9fafb;
    --color-gray-100: #f3f4f6;
    --color-gray-200: #e5e7eb;
    --color-gray-300: #d1d5db;
    --color-gray-500: #6b7280;
    --color-gray-700: #374151;
    --color-gray-900: #111827;

    /* Semantic neutrals */
    --color-text: var(--color-gray-900);
    --color-text-light: var(--color-gray-500);
    --color-background: white;
    --color-background-alt: var(--color-gray-50);
    --color-border: var(--color-gray-200);

    /* Status colors */
    --color-success: #10b981;
    --color-warning: #f59e0b;
    --color-error: #ef4444;
    --color-info: #3b82f6;

    /* ========================================
       TYPOGRAPHY TOKENS
       ======================================== */

    /* Font families */
    --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    --font-mono: 'Courier New', Courier, monospace;

    /* Font sizes (modular scale) */
    --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;

    /* ========================================
       SPACING TOKENS
       ======================================== */

    --spacing-xs: 0.25rem;   /* 4px */
    --spacing-sm: 0.5rem;    /* 8px */
    --spacing-md: 1rem;      /* 16px */
    --spacing-lg: 1.5rem;    /* 24px */
    --spacing-xl: 2rem;      /* 32px */
    --spacing-2xl: 3rem;     /* 48px */
    --spacing-3xl: 4rem;     /* 64px */

    /* ========================================
       BORDER & RADIUS TOKENS
       ======================================== */

    --border-width: 1px;
    --border-width-thick: 2px;

    --radius-sm: 0.25rem;
    --radius-md: 0.5rem;
    --radius-lg: 1rem;
    --radius-full: 9999px;

    /* ========================================
       SHADOW TOKENS
       ======================================== */

    --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
    --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
    --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);

    /* ========================================
       TRANSITION TOKENS
       ======================================== */

    --transition-fast: 150ms;
    --transition-base: 300ms;
    --transition-slow: 500ms;

    --easing-standard: cubic-bezier(0.4, 0.0, 0.2, 1);
    --easing-in: cubic-bezier(0.4, 0.0, 1, 1);
    --easing-out: cubic-bezier(0.0, 0.0, 0.2, 1);
}

Using Design Tokens in Components

/* Components built from tokens are consistent and themeable */
.button {
    font-family: var(--font-sans);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    padding: var(--spacing-sm) var(--spacing-lg);
    border-radius: var(--radius-md);
    border: var(--border-width) solid transparent;
    background: var(--color-primary);
    color: white;
    box-shadow: var(--shadow-sm);
    transition: all var(--transition-base) var(--easing-standard);
}

.button:hover {
    background: var(--color-primary-hover);
    box-shadow: var(--shadow-md);
}

.card {
    background: var(--color-background);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--spacing-lg);
    box-shadow: var(--shadow-md);
}

.heading {
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-tight);
    color: var(--color-text);
    margin-bottom: var(--spacing-md);
}

Benefits of design tokens:

Building a Button Component Library

Buttons are perfect for demonstrating component design because they appear everywhere and need consistent behavior while supporting many variants. A button component library handles all button styling needs across a project.

Base Button Styles

Example: Base button component with variants

/* Base button - shared by all variants */
.button {
    /* Reset browser button styles */
    display: inline-block;
    font-family: inherit;
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    line-height: 1;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    border: var(--border-width) solid transparent;
    border-radius: var(--radius-md);
    padding: var(--spacing-sm) var(--spacing-lg);
    transition: all var(--transition-base) var(--easing-standard);
    /* Prevents button from being highlighted when clicked */
    -webkit-tap-highlight-color: transparent;
}

.button:focus {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

.button:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Primary variant - main call-to-action */
.button--primary {
    background: var(--color-primary);
    color: white;
}

.button--primary:hover:not(:disabled) {
    background: var(--color-primary-hover);
    box-shadow: var(--shadow-md);
}

/* Secondary variant - less prominent */
.button--secondary {
    background: var(--color-gray-100);
    color: var(--color-text);
}

.button--secondary:hover:not(:disabled) {
    background: var(--color-gray-200);
}

/* Outline variant - borders only */
.button--outline {
    background: transparent;
    border-color: var(--color-primary);
    color: var(--color-primary);
}

.button--outline:hover:not(:disabled) {
    background: var(--color-primary-light);
}

/* Destructive variant - dangerous actions */
.button--danger {
    background: var(--color-error);
    color: white;
}

.button--danger:hover:not(:disabled) {
    background: #dc2626;  /* Darker red */
}

/* Size modifiers */
.button--small {
    font-size: var(--font-size-sm);
    padding: var(--spacing-xs) var(--spacing-md);
}

.button--large {
    font-size: var(--font-size-lg);
    padding: var(--spacing-md) var(--spacing-xl);
}

/* Full-width modifier */
.button--block {
    display: block;
    width: 100%;
}

Button HTML Usage

<!-- Primary button -->
<button class="button button--primary">Save Changes</button>

<!-- Large secondary button -->
<button class="button button--secondary button--large">Cancel</button>

<!-- Small danger button -->
<button class="button button--danger button--small">Delete</button>

<!-- Outline button -->
<button class="button button--outline">Learn More</button>

<!-- Full-width primary button -->
<button class="button button--primary button--block">
    Sign Up Now
</button>

<!-- Disabled button -->
<button class="button button--primary" disabled>
    Processing...
</button>

<!-- Link styled as button -->
<a href="/signup" class="button button--primary">Get Started</a>

Creating Card Components

Cards group related content into self-contained units. A card component system handles common patterns while allowing flexibility for different content types.

Example: Flexible card component

/* Base card styles */
.card {
    background: var(--color-background);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    overflow: hidden;
    transition: box-shadow var(--transition-base) var(--easing-standard);
}

.card:hover {
    box-shadow: var(--shadow-lg);
}

/* Card elements */
.card__image {
    width: 100%;
    height: 200px;
    object-fit: cover;
    display: block;
}

.card__header {
    padding: var(--spacing-lg);
    border-bottom: var(--border-width) solid var(--color-border);
}

.card__body {
    padding: var(--spacing-lg);
}

.card__footer {
    padding: var(--spacing-lg);
    border-top: var(--border-width) solid var(--color-border);
    background: var(--color-background-alt);
}

.card__title {
    font-size: var(--font-size-xl);
    font-weight: var(--font-weight-bold);
    color: var(--color-text);
    margin: 0 0 var(--spacing-sm) 0;
}

.card__subtitle {
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    margin: 0;
}

.card__description {
    color: var(--color-text);
    line-height: var(--line-height-relaxed);
    margin: 0;
}

/* Card modifiers */
.card--horizontal {
    display: flex;
}

.card--horizontal .card__image {
    width: 40%;
    height: auto;
}

.card--horizontal .card__body {
    width: 60%;
}

.card--clickable {
    cursor: pointer;
    transition: all var(--transition-base) var(--easing-standard);
}

.card--clickable:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-xl);
}

.card--featured {
    border-color: var(--color-primary);
    border-width: var(--border-width-thick);
}

Form Component Patterns

Forms require consistent styling for inputs, labels, validation states, and layout. A form component system ensures all forms look and behave uniformly.

Example: Form component system

/* Form field container */
.form-field {
    margin-bottom: var(--spacing-lg);
}

/* Labels */
.form-label {
    display: block;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    margin-bottom: var(--spacing-xs);
}

.form-label--required::after {
    content: " *";
    color: var(--color-error);
}

/* Inputs */
.form-input {
    display: block;
    width: 100%;
    font-family: inherit;
    font-size: var(--font-size-base);
    padding: var(--spacing-sm) var(--spacing-md);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-background);
    color: var(--color-text);
    transition: all var(--transition-base) var(--easing-standard);
}

.form-input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px var(--color-primary-light);
}

.form-input::placeholder {
    color: var(--color-text-light);
}

/* Validation states */
.form-input--error {
    border-color: var(--color-error);
}

.form-input--error:focus {
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}

.form-input--success {
    border-color: var(--color-success);
}

/* Help text */
.form-help {
    display: block;
    font-size: var(--font-size-sm);
    color: var(--color-text-light);
    margin-top: var(--spacing-xs);
}

.form-help--error {
    color: var(--color-error);
}

/* Textarea */
.form-textarea {
    min-height: 120px;
    resize: vertical;
}

/* Select dropdown */
.form-select {
    background-image: url("data:image/svg+xml,..."); /* Custom dropdown arrow */
    background-repeat: no-repeat;
    background-position: right var(--spacing-sm) center;
    padding-right: calc(var(--spacing-lg) + 1rem);
    appearance: none;
}

/* Checkbox and radio */
.form-checkbox,
.form-radio {
    display: inline-flex;
    align-items: center;
}

.form-checkbox input,
.form-radio input {
    margin-right: var(--spacing-sm);
}

CSS Architecture and File Organization

As projects grow, organizing CSS files becomes critical for maintainability. Several architecture patterns provide structure for scaling CSS.

Component-Based File Structure

Organize CSS files by component, with each file focused on one component:

styles/
├── base/
│   ├── reset.css          /* CSS reset/normalize */
│   ├── typography.css     /* Base typography styles */
│   └── global.css         /* Global base styles */
├── tokens/
│   ├── colors.css         /* Color design tokens */
│   ├── spacing.css        /* Spacing design tokens */
│   ├── typography.css     /* Typography tokens */
│   └── shadows.css        /* Shadow tokens */
├── components/
│   ├── button.css         /* Button component */
│   ├── card.css           /* Card component */
│   ├── form.css           /* Form components */
│   ├── modal.css          /* Modal component */
│   └── navigation.css     /* Navigation component */
├── layouts/
│   ├── header.css         /* Site header layout */
│   ├── footer.css         /* Site footer layout */
│   └── grid.css           /* Page grid layouts */
├── utilities/
│   ├── spacing.css        /* Margin/padding utilities */
│   ├── text.css           /* Text utilities */
│   └── display.css        /* Display utilities */
└── themes/
    ├── light.css          /* Light theme overrides */
    └── dark.css           /* Dark theme overrides */

CSS Import Order

Import files in specificity order, from least to most specific:

/* main.css - master import file */

/* 1. Design tokens */
@import 'tokens/colors.css';
@import 'tokens/spacing.css';
@import 'tokens/typography.css';

/* 2. Base/reset styles */
@import 'base/reset.css';
@import 'base/typography.css';
@import 'base/global.css';

/* 3. Layout systems */
@import 'layouts/header.css';
@import 'layouts/footer.css';
@import 'layouts/grid.css';

/* 4. Components */
@import 'components/button.css';
@import 'components/card.css';
@import 'components/form.css';
@import 'components/modal.css';
@import 'components/navigation.css';

/* 5. Utilities (highest specificity) */
@import 'utilities/spacing.css';
@import 'utilities/text.css';
@import 'utilities/display.css';

/* 6. Theme overrides */
@import 'themes/dark.css' (prefers-color-scheme: dark);

Theme Systems and Dark Mode

CSS custom properties make theme switching straightforward. Define color tokens that change based on theme, and all components update automatically.

Implementing Dark Mode

Example: Theme system with light and dark modes

/* Default light theme */
:root {
    --color-background: white;
    --color-background-alt: #f9fafb;
    --color-text: #111827;
    --color-text-light: #6b7280;
    --color-border: #e5e7eb;
    --shadow-color: rgba(0, 0, 0, 0.1);
}

/* Dark theme overrides */
@media (prefers-color-scheme: dark) {
    :root {
        --color-background: #1f2937;
        --color-background-alt: #111827;
        --color-text: #f9fafb;
        --color-text-light: #9ca3af;
        --color-border: #374151;
        --shadow-color: rgba(0, 0, 0, 0.5);
    }
}

/* Manual theme switching with data attribute */
[data-theme="dark"] {
    --color-background: #1f2937;
    --color-background-alt: #111827;
    --color-text: #f9fafb;
    --color-text-light: #9ca3af;
    --color-border: #374151;
    --shadow-color: rgba(0, 0, 0, 0.5);
}

/* Components automatically use themed colors */
body {
    background: var(--color-background);
    color: var(--color-text);
}

.card {
    background: var(--color-background);
    border-color: var(--color-border);
    box-shadow: 0 2px 4px var(--shadow-color);
}

.heading {
    color: var(--color-text);
}

JavaScript Theme Switcher

// Simple theme switcher with localStorage
function toggleTheme() {
    const html = document.documentElement;
    const currentTheme = html.getAttribute('data-theme');
    const newTheme = currentTheme === 'dark' ? 'light' : 'dark';

    html.setAttribute('data-theme', newTheme);
    localStorage.setItem('theme', newTheme);
}

// Load saved theme on page load
window.addEventListener('DOMContentLoaded', () => {
    const savedTheme = localStorage.getItem('theme');
    if (savedTheme) {
        document.documentElement.setAttribute('data-theme', savedTheme);
    }
});

Worked Example: Complete Design System

This example brings together all concepts into a mini design system with tokens, components, and theming.

Design Tokens

/* tokens.css */
:root {
    /* Colors */
    --color-primary: #2563eb;
    --color-success: #10b981;
    --color-warning: #f59e0b;
    --color-error: #ef4444;

    /* Light theme defaults */
    --color-bg: white;
    --color-text: #111827;
    --color-border: #e5e7eb;

    /* Spacing scale */
    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 1rem;
    --space-4: 1.5rem;
    --space-5: 2rem;

    /* Typography */
    --font-size-sm: 0.875rem;
    --font-size-base: 1rem;
    --font-size-lg: 1.125rem;
    --font-weight-normal: 400;
    --font-weight-bold: 700;

    /* Borders and radius */
    --radius: 0.5rem;
    --border-width: 1px;
}

/* Dark theme */
[data-theme="dark"] {
    --color-bg: #1f2937;
    --color-text: #f9fafb;
    --color-border: #374151;
}

Button Component

/* components/button.css */
.btn {
    display: inline-block;
    padding: var(--space-2) var(--space-4);
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    border-radius: var(--radius);
    border: var(--border-width) solid transparent;
    cursor: pointer;
    transition: all 300ms ease;
}

.btn--primary {
    background: var(--color-primary);
    color: white;
}

.btn--primary:hover {
    background: #1d4ed8;
}

.btn--success {
    background: var(--color-success);
    color: white;
}

Card Component

/* components/card.css */
.card {
    background: var(--color-bg);
    border: var(--border-width) solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-4);
}

.card__title {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
    color: var(--color-text);
    margin-bottom: var(--space-2);
}

.card__body {
    color: var(--color-text);
}

This system automatically adapts to dark mode, maintains consistency through tokens, and makes it trivial to add new components that fit the design.

Practice Opportunity

Build a complete component library to solidify your understanding.

Challenge: Create Your Own Design System

Build a mini design system with these requirements:

  1. Design tokens file with:
    • Color palette (primary, secondary, neutrals, status colors)
    • Spacing scale (at least 6 values)
    • Typography scale (font sizes, weights, line heights)
    • Border radius and shadow values
  2. At least 3 components using BEM:
    • Button component with 3 variants
    • Card component with header/body/footer
    • Alert component for success/warning/error messages
  3. Dark mode support that changes at least 5 token values
  4. Organized file structure separating tokens, components, and utilities

Bonus Challenges

Summary of Key Concepts

This lesson covered the foundations of scalable, maintainable CSS:

Component-Based Design

BEM Methodology

CSS Custom Properties

Design Systems

CSS Architecture

Next Steps

With component design mastery, you're ready for the final advanced technique: Lesson 13: CSS Animations & Transitions. This lesson teaches how to add motion and interactivity to your components using CSS animations, transitions, transforms, and pure CSS interactive patterns like accordions and modals—all without JavaScript.

Before moving on, practice building component libraries for real projects. Try creating a design system for a personal project, or rebuild components from sites you admire using BEM and CSS variables. The skills you've learned prepare you for professional development and modern frameworks.

Bibliography

Yandex. "BEM: Block Element Modifier." BEM Methodology. https://en.bem.info/methodology/

MDN Web Docs. "Using CSS custom properties (variables)." Mozilla Developer Network. https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties

Frost, Brad. "Atomic Design." Brad Frost Web. https://bradfrost.com/blog/post/atomic-web-design/

Coyier, Chris. "The Different Logical Ways to Group CSS Code." CSS-Tricks. https://css-tricks.com/different-logical-ways-group-css-properties/

GitHub. "Primer Design System." GitHub Design Systems. https://primer.style/

Fanguy, Will. "Design Tokens for Dummies." UX Collective. 2019.