Skip to main content
The Stride Design System features a comprehensive multi-brand architecture that enables you to build applications with multiple distinct brand identities. The system supports two types of brands:
  • Static brands: Five pre-built brands (Stride, Coral, Forest, Runswap, Acme) with complete token definitions
  • Dynamic brands: Runtime white-label system for creating custom brands with automatic fallbacks

Architecture

The brand system is built on three layers:

1. Core Tokens

Foundation color palettes that define the base colors for each brand:
interface CoreBrandTokens {
  primary?: {     // 11 shades (50-950)
    50?: string;
    500?: string; // Main brand color
    900?: string;
  };
  neutral?: {     // Grayscale (0, 50-950)
    0?: string;   // Pure white
    500?: string; // Mid-gray
    950?: string; // Near black
  };
  success?: { /* 5 shades */ };
  warning?: { /* 5 shades */ };
  danger?: { /* 5 shades */ };
}

2. Semantic Tokens

Purpose-driven tokens mapped to core colors:
interface SemanticBrandTokens {
  // Text
  textPrimary?: string;           // Main text color
  textSecondary?: string;         // Secondary text
  textLink?: string;              // Link color
  
  // Backgrounds
  bgPrimary?: string;             // Main background
  bgSecondary?: string;           // Card/section backgrounds
  
  // Interactive
  interactivePrimary?: string;    // Primary buttons
  interactivePrimaryHover?: string;
  
  // Borders & Status
  borderPrimary?: string;
  statusSuccess?: string;
  statusDanger?: string;
  // ... 40+ semantic tokens
}

3. Component Tokens

Component-specific customizations:
interface LayoutBrandTokens {
  fontFamilyPrimary?: string;     // 'Inter', 'Poppins', etc.
  radiusButton?: string;          // Button border radius
  spacingScale?: number;          // Spacing multiplier
  shadowMd?: string;              // Shadows
}

Static vs Dynamic Brands

Static Brands

Pre-configured brands defined in CSS with complete token sets:
import { applyBrandTheme } from 'stride-ds';

// Switch to a static brand
applyBrandTheme('coral');
applyBrandTheme('forest');
applyBrandTheme('stride');
Behind the scenes, this adds a CSS class:
/* Applied to <html> element */
.brand-coral {
  --brand-primary-500: #f97316;
  --brand-neutral-900: #5c3530;
  --text-primary: var(--brand-neutral-900);
  --font-family-primary: 'Poppins', sans-serif;
  --radius-button: 0; /* Coral has no button radius */
}

Dynamic Brands

Runtime white-label brands with automatic fallbacks:
import { registerDynamicBrand, applyBrandTheme } from 'stride-ds';

// Register a custom brand
registerDynamicBrand({
  id: 'acme-corp',
  name: 'Acme Corporation',
  tokens: {
    core: {
      primary: {
        500: '#7c3aed', // Only define what you need
        600: '#6d28d9',
      }
    },
    semantic: {
      textBrand: '#7c3aed',
    },
    typography: {
      fontFamilyPrimary: 'Montserrat, sans-serif',
    }
  },
  fallback: {
    brand: 'stride',           // Use Stride for undefined tokens
    useSemanticFallback: true, // Inherit semantic mappings
  }
});

// Apply the dynamic brand
applyBrandTheme('acme-corp');
Dynamic brands generate CSS at runtime:
/* Generated automatically */
.brand-dynamic-acme-corp {
  --brand-primary-500: #7c3aed;
  --brand-primary-600: #6d28d9;
  --text-brand: #7c3aed;
  --font-family-primary: Montserrat, sans-serif;
}

Brand Initialization

Client-Side Setup

Use the BrandInitializer component to set up brands on mount:
// app/layout.tsx
import { BrandInitializer } from 'stride-ds';

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <BrandInitializer />
        {children}
      </body>
    </html>
  );
}
The component automatically:
  • Restores saved brand from localStorage
  • Restores all registered dynamic brands
  • Applies the active brand’s CSS classes

Manual Initialization

import { initializeBrand } from 'stride-ds';

// Call once when your app starts
initializeBrand();

React Hook

Manage brands reactively with the useBrand hook:
import { useBrand } from 'stride-ds';

function BrandSwitcher() {
  const { 
    currentBrand,           // Current brand ID
    currentBrandType,       // 'static' | 'dynamic'
    availableBrands,        // All static brands
    dynamicBrands,          // All dynamic brands
    setBrand,               // Switch brands
    registerDynamicBrand,   // Register new brand
  } = useBrand();

  return (
    <select 
      value={currentBrand} 
      onChange={(e) => setBrand(e.target.value)}
    >
      {availableBrands.map(brand => (
        <option key={brand.id} value={brand.id}>
          {brand.name}
        </option>
      ))}
    </select>
  );
}

Brand Comparison

Stride

Blue • Outfit/Inter • Default design system

Coral

Orange • Poppins • No button radius

Forest

Green • Roboto • 1.2× spacing scale

Runswap

Pink • Outfit/Nunito • Bold and vibrant

Acme

Indigo • Inter/JetBrains Mono • Tech aesthetic

Key Features

Automatic Dark Mode

All brands support dark mode automatically:
// Toggle dark mode
document.documentElement.classList.toggle('dark');

// Dark mode tokens are automatically applied
// .brand-stride.dark { ... }

LocalStorage Persistence

Brand selection persists across sessions:
// Automatically saved to localStorage
applyBrandTheme('coral');

// Restored on next visit
initializeBrand(); // Applies 'coral' from storage

Smooth Transitions

Optional brand-switch transitions:
import { configureDynamicBrandSystem } from 'stride-ds';

configureDynamicBrandSystem({
  enableTransitions: true,
  transitionDuration: 200, // ms
});

Type Safety

Full TypeScript support:
import type { 
  BrandTheme, 
  DynamicBrandConfig,
  CoreBrandTokens,
  SemanticBrandTokens 
} from 'stride-ds';

Next Steps

Build docs developers (and LLMs) love