Customizing

Learn how to customize Luma's design tokens using CSS variables and Tailwind utilities. All tokens can be overridden at runtime without rebuilding your application.

Overview

Luma uses CSS custom properties (CSS variables) for all design tokens. This enables powerful runtime customization patterns:

  • Global theme overrides: Change one token, update all components
  • Component-specific styling: Use Tailwind utilities for instance-level customization
  • Scoped overrides: Apply custom tokens to specific sections of your app
  • Dark theme customization: Different values for light and dark modes

All Customizable Tokens

Complete reference of all 57 design tokens available for customization.

Primary Color Scale (12 steps)

Radix UI inspired 12-step scale. Step 5 is the base brand color.

:root {
  /* Primary Color Scale (12 steps) */
  --color-primary-1: oklch(1 0 300);           /* Lightest */
  --color-primary-2: oklch(0.94 0.020 300);
  --color-primary-3: oklch(0.88 0.035 300);
  --color-primary-4: oklch(0.78 0.060 300);
  --color-primary-5: oklch(0.48 0.090 300);    /* BASE COLOR */
  --color-primary-6: oklch(0.43 0.085 300);
  --color-primary-7: oklch(0.38 0.080 300);
  --color-primary-8: oklch(0.33 0.075 300);
  --color-primary-9: oklch(0.28 0.065 300);
  --color-primary-10: oklch(0.23 0.055 300);
  --color-primary-11: oklch(0.18 0.045 300);
  --color-primary-12: oklch(0.13 0.030 300);   /* Darkest */
}

Gray Scale (12 steps)

Theme-independent neutral colors for structural elements.

:root {
  /* Gray Scale (12 steps) - Theme-independent */
  --color-gray-1: oklch(0.99 0.000 0);         /* Lightest */
  --color-gray-2: oklch(0.98 0.000 0);
  --color-gray-3: oklch(0.95 0.000 0);         /* Border color */
  --color-gray-4: oklch(0.92 0.000 0);
  --color-gray-5: oklch(0.89 0.000 0);
  --color-gray-6: oklch(0.86 0.000 0);
  --color-gray-7: oklch(0.82 0.000 0);
  --color-gray-8: oklch(0.76 0.000 0);
  --color-gray-9: oklch(0.60 0.000 0);
  --color-gray-10: oklch(0.57 0.000 0);
  --color-gray-11: oklch(0.45 0.000 0);        /* Muted text */
  --color-gray-12: oklch(0.20 0.000 0);        /* Darkest */
}

Surface Colors

Background and foreground colors for app surfaces.

:root {
  /* Surface Colors */
  --color-background: oklch(1 0 0);                  /* App background */
  --color-foreground: oklch(0.22 0.014 290);         /* Primary text */
  --color-popover: oklch(0.13 0.030 300);            /* Tooltip bg */
  --color-popover-foreground: oklch(1 0 0);          /* Tooltip text */
}

Semantic State Colors

Colors for destructive, warning, and success states.

:root {
  /* Semantic State Colors */
  --color-destructive: oklch(0.63 0.10 28);          /* Error/delete */
  --color-destructive-foreground: oklch(1 0 0);      /* Text on destructive */
  --color-warning: oklch(0.80 0.09 95);              /* Warning/caution */
  --color-warning-foreground: oklch(0.22 0.014 290); /* Text on warning */
  --color-success: oklch(0.72 0.07 155);             /* Success/confirm */
  --color-success-foreground: oklch(1 0 0);          /* Text on success */
}

Border Radius (6 tokens)

Consistent rounded corners across components.

:root {
  /* Border Radius (6 tokens) */
  --radius-1: 0.125rem;  /* 2px - minimal */
  --radius-2: 0.25rem;   /* 4px - badges, pills */
  --radius-3: 0.375rem;  /* 6px - tooltips */
  --radius-4: 0.5rem;    /* 8px - buttons, inputs (default) */
  --radius-5: 0.75rem;   /* 12px - cards */
  --radius-6: 1rem;      /* 16px - modals */
}

Shadows (6 tokens)

Elevation levels for depth hierarchy.

:root {
  /* Shadows (6 elevation levels) */
  --shadow-1: inset 0 0 0 1px oklch(0.5 0 0 / 0.03);
  --shadow-2: 0 1px 2px 0 oklch(0 0 0 / 0.03), 0 0 0 1px oklch(0.5 0 0 / 0.02);
  --shadow-3: 0 2px 4px 0 oklch(0 0 0 / 0.04), 0 0 0 1px oklch(0.5 0 0 / 0.02);
  --shadow-4: 0 4px 8px 0 oklch(0 0 0 / 0.06), 0 0 0 1px oklch(0.5 0 0 / 0.02);
  --shadow-5: 0 8px 16px 0 oklch(0 0 0 / 0.08), 0 0 0 1px oklch(0.5 0 0 / 0.02);
  --shadow-6: 0 16px 32px 0 oklch(0 0 0 / 0.10), 0 0 0 1px oklch(0.5 0 0 / 0.02);
}

Typography (1 token)

Base font family with fallback stack.

:root {
  /* Typography */
  --font-family-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

Customization Patterns

Override Primary Color

Change your brand color globally by overriding the primary token in your app's CSS. This affects all buttons, badges, toasts, and any component using bg-primary.

:root {
  --color-primary: oklch(0.60 0.15 180);  /* Cyan instead of purple */
  --color-primary-foreground: oklch(1 0 0);
}

/* Now all buttons, badges, toasts, and links use cyan */

Component-Specific Overrides

Use Tailwind utilities via the class or className prop to customize individual component instances without affecting others.

<!-- Custom button with accent color -->
<button lumaButton class="bg-accent hover:bg-accent/80">
  Custom Button
</button>

<!-- Card with muted background and accent border -->
<luma-card class="bg-muted border-accent">
  Custom Card
</luma-card>

<!-- Multiple overrides -->
<div class="bg-primary/10 text-primary border-2 border-primary/20 rounded-lg p-4">
  Custom Container
</div>

Dark Theme Customization

Customize token values specifically for dark mode. These values apply automatically when <html class="dark"> is set.

.dark {
  --color-primary: oklch(0.75 0.12 340);  /* Pink in dark mode */
  --color-background: oklch(0.15 0.006 290);
  --color-foreground: oklch(0.98 0.000 0);
}

/* Automatically applies when <html class="dark"> */

Scoped Token Overrides

Apply custom token values to specific sections of your app. All Luma components inside the scoped selector will use the overridden values.

.my-feature {
  --color-primary: oklch(0.70 0.12 340);  /* Pink theme */
  --radius-4: 0.25rem;  /* Sharper corners */
  --shadow-3: 0 4px 6px -1px oklch(0 0 0 / 0.1);
}

/* All Luma components inside .my-feature use these values */

Using Tailwind Utilities

All semantic tokens are available as standard Tailwind utilities. Use them to compose custom styles without writing CSS.

<!-- Background colors -->
<div class="bg-primary">Primary background</div>
<div class="bg-secondary">Secondary background</div>
<div class="bg-muted">Muted background</div>

<!-- Text colors -->
<p class="text-foreground">Primary text</p>
<p class="text-muted-foreground">Secondary text</p>
<p class="text-primary">Branded text</p>

<!-- Border colors -->
<div class="border border-border">Default border</div>
<div class="border-2 border-primary">Primary border</div>

<!-- Border radius -->
<div class="rounded-md">Medium radius (--radius-4)</div>
<div class="rounded-lg">Large radius (--radius-5)</div>

Opacity Modifiers

Tailwind's inline opacity modifiers work with all Luma semantic tokens. Use them for subtle backgrounds, hover states, and layered effects.

<!-- Subtle backgrounds -->
<div class="bg-primary/10">10% opacity primary</div>
<div class="bg-destructive/20">20% opacity destructive</div>

<!-- Hover states -->
<button class="bg-primary hover:bg-primary/90">
  Hover darkens slightly
</button>

<!-- Layered effects -->
<div class="bg-primary/5 border border-primary/20">
  <p class="text-primary/85">Subtle branded container</p>
</div>

<!-- Complex composition -->
<div class="bg-muted/50 backdrop-blur-sm border border-border/50">
  Glass morphism effect
</div>