Skip to main content

Overview

Stride Design System uses a powerful CSS variable-based theming architecture that separates foundation tokens (spacing, radius, shadows) from semantic tokens (colors, interactive states). This separation enables:
  • Consistent design language across brands
  • Automatic dark/light mode support
  • Easy customization without touching component code
  • Runtime theme switching

Token Architecture

Foundation Tokens

Foundation tokens define the base design language and are brand-agnostic. These are defined in styles.css:
:root {
  --spacing-xs: 0.25rem;   /* 4px */
  --spacing-sm: 0.5rem;    /* 8px */
  --spacing-md: 0.75rem;   /* 12px */
  --spacing-lg: 1rem;      /* 16px */
  --spacing-xl: 1.5rem;    /* 24px */
  --spacing-2xl: 2rem;     /* 32px */
  --spacing-3xl: 3rem;     /* 48px */
  --spacing-4xl: 4rem;     /* 64px */
  --spacing-5xl: 6rem;     /* 96px */
}

Semantic Tokens

Semantic tokens map to specific UI purposes and adapt per brand. Defined in brands.css:
.brand-stride {
  --text-primary: var(--brand-neutral-900);    /* Main text */
  --text-secondary: var(--brand-neutral-600);  /* Subtitles */
  --text-tertiary: var(--brand-neutral-500);   /* Captions */
  --text-inverse: var(--brand-neutral-0);      /* On dark bg */
  --text-disabled: var(--brand-neutral-400);   /* Disabled */
  --text-link: var(--brand-primary-600);       /* Links */
  --text-link-hover: var(--brand-primary-700); /* Link hover */
}

Component Tokens

Component-specific tokens for consistent sizing and spacing:
Component Tokens
:root {
  /* Button sizing */
  --button-height-sm: 2rem;      /* 32px */
  --button-height-md: 2.5rem;    /* 40px */
  --button-height-lg: 3rem;      /* 48px */
  --button-padding-sm: 0 0.75rem;
  --button-padding-md: 0 1rem;
  --button-padding-lg: 0 1.5rem;
  --radius-button: var(--radius-full); /* Pill-shaped by default */
  
  /* Input sizing */
  --input-height-sm: 2.25rem;    /* 36px */
  --input-height-md: 2.75rem;    /* 44px */
  --input-height-lg: 3.25rem;    /* 52px */
  
  /* Card tokens */
  --card-padding-sm: 1rem;
  --card-padding-md: 1.5rem;
  --card-padding-lg: 2rem;
  --card-radius: var(--radius-3xl); /* 24px */
}

Dark Mode Support

Each brand has automatic dark mode variants that adapt semantic tokens:
.brand-stride {
  --text-primary: var(--brand-neutral-900);  /* Dark text */
  --bg-primary: var(--brand-neutral-0);      /* White bg */
  --border-primary: var(--brand-neutral-200); /* Light border */
}

Toggling Dark Mode

// Toggle dark mode
function toggleDarkMode() {
  const html = document.documentElement;
  html.classList.toggle('dark');
}

Using Tokens in Components

Components reference semantic tokens using CSS custom properties:
import { cva } from 'class-variance-authority';
import { cn } from '@/lib/utils';

const buttonVariants = cva(
  [
    'inline-flex items-center justify-center',
    '[border-radius:var(--radius-button)]',
    '[transition-duration:var(--transition-normal)]',
  ],
  {
    variants: {
      variant: {
        primary: [
          '[background-color:var(--interactive-primary)]',
          '[color:var(--interactive-primary-text)]',
          'hover:[background-color:var(--interactive-primary-hover)]',
        ],
        secondary: [
          '[background-color:var(--interactive-secondary)]',
          '[color:var(--text-primary)]',
        ],
      },
      size: {
        sm: '[height:var(--button-height-sm)]',
        md: '[height:var(--button-height-md)]',
        lg: '[height:var(--button-height-lg)]',
      },
    },
  }
);

Tailwind CSS v4 Integration

Stride uses Tailwind v4 with inline theme configuration that maps to semantic tokens:
Tailwind Theme Mapping
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --font-sans: var(--font-family-primary);
  
  /* Brand-aware color mapping */
  --color-primary: var(--interactive-primary);
  --color-success: var(--status-success);
  --color-warning: var(--status-warning);
  --color-danger: var(--status-danger);
  
  /* Semantic neutral scale */
  --color-neutral-0: var(--bg-primary);
  --color-neutral-100: var(--bg-tertiary);
  --color-neutral-800: var(--text-primary);
}
This allows you to use Tailwind utilities like bg-primary or text-neutral-800 that automatically adapt to the active brand and theme.

Best Practices

Instead of hardcoding colors or using brand tokens directly, use semantic tokens:
// ❌ Bad - hardcoded color
<div className="bg-[#0ea5e9]" />

// ❌ Bad - brand-specific token
<div className="bg-[var(--brand-primary-500)]" />

// ✅ Good - semantic token
<div className="bg-[var(--interactive-primary)]" />
Use component tokens for consistent sizing:
// ✅ Good - uses component token
<button className="h-[var(--button-height-md)]" />

// ✅ Good - uses spacing token
<div className="p-[var(--spacing-lg)]" />
Always verify your components work in both themes:
// Toggle dark mode during testing
document.documentElement.classList.add('dark');
document.documentElement.classList.remove('dark');
Combine Tailwind classes safely with the cn() utility:
import { cn } from '@/lib/utils';

function Component({ className }) {
  return (
    <div className={cn('base-classes', 'default-styles', className)} />
  );
}

Next Steps

Multi-brand System

Learn how to switch between brands and create custom brand themes

Customization

Override tokens and customize components for your needs

Accessibility

Understand how theming supports accessible design patterns

Component Library

Explore all components built with the token system

Build docs developers (and LLMs) love