Design System Problems

Dark Mode Token Structure

January 15, 2026 • 5 min read

Dark Mode Token Structure

Dark mode token structure determines how a design system organizes tokens to support both light and dark color schemes. Implementing dark mode is not simply inverting colors but rather creating a parallel token layer that maintains visual hierarchy, accessibility, and brand identity in a different luminance context. Proper token structure makes theme switching seamless while keeping the system maintainable.

What Is Dark Mode Token Structure

Dark mode token structure refers to the organizational patterns and relationships between tokens that enable dark theme support. This encompasses how light and dark token sets relate to each other, which tokens change between themes and which remain constant, and how the build and runtime systems switch between token sets.

Effective dark mode structure recognizes that dark mode is not an afterthought but a first-class theme variant requiring intentional design and architectural support from the token layer.

How Dark Mode Token Structure Works

The foundation of dark mode support lies in semantic token architecture. Primitive tokens define the full color palette for both themes. Semantic tokens reference different primitives depending on the active theme.

A primitive layer might include:

color.primitive.gray.50: #fafafa
color.primitive.gray.900: #171717
color.primitive.blue.400: #60a5fa
color.primitive.blue.600: #2563eb

Semantic tokens for light mode:

color.background.primary: {color.primitive.white}
color.text.primary: {color.primitive.gray.900}
color.interactive.primary: {color.primitive.blue.600}

Semantic tokens for dark mode:

color.background.primary: {color.primitive.gray.900}
color.text.primary: {color.primitive.gray.50}
color.interactive.primary: {color.primitive.blue.400}

Components reference only semantic tokens, gaining automatic theme support:

.card {
  background: var(--color-background-primary);
  color: var(--color-text-primary);
}

Build processes generate theme-specific outputs. CSS output might use scoped custom properties:

:root {
  --color-background-primary: #ffffff;
}

[data-theme="dark"] {
  --color-background-primary: #171717;
}

Theme switching at runtime toggles the data attribute, and CSS cascade applies the appropriate values.

Key Considerations

Common Questions

Should dark mode use inverted colors?

Simple inversion rarely produces good dark mode results. Inverting light mode colors creates harsh contrasts, incorrect semantic meanings, and accessibility failures. Dark mode requires intentional color selection, not mechanical transformation.

Effective dark mode maintains visual hierarchy while adapting to the different luminance context. In light mode, hierarchy often progresses from white backgrounds through light grays to darker elements. Dark mode reverses this direction, with near-black backgrounds progressing through dark grays to lighter elements.

However, the specific gray values differ. Dark mode benefits from slightly elevated base surfaces (gray-900 rather than true black) and more moderate contrast steps. Primary actions might use lighter color variants that maintain visibility without creating glare.

Semantic color mapping handles these differences. The same semantic token (color.background.elevated) resolves to appropriate values for each theme without component code needing theme awareness.

How should elevation work in dark mode?

Light mode typically uses shadows to convey elevation. Elements that appear closer cast larger, more diffuse shadows. Dark mode presents challenges because shadows become nearly invisible against dark backgrounds.

Alternative approaches for dark mode elevation include surface color variation, where elevated surfaces are slightly lighter than the base. Material Design popularized this approach, where each elevation level adds subtle lightness to the surface color.

Token structure for elevation-aware surfaces:

// Light mode uses single surface color; elevation via shadows
color.background.surface: {color.primitive.white}
elevation.shadow.md: 0 4px 6px rgba(0,0,0,0.1)

// Dark mode uses graduated surface colors
color.background.surface: {color.primitive.gray.900}
color.background.surface.raised: {color.primitive.gray.800}
color.background.surface.overlay: {color.primitive.gray.700}

Components using elevation need to reference the appropriate surface color rather than relying solely on shadows. This may require component adjustments when dark mode is added to existing systems.

How should the theme preference be detected and stored?

Operating systems expose user color scheme preferences through media queries. The prefers-color-scheme media query detects whether the user has requested light or dark appearance:

@media (prefers-color-scheme: dark) {
  :root {
    --color-background-primary: #171717;
  }
}

This provides a sensible default but users may want to override the system preference for specific applications. A three-state preference (light, dark, system) gives users control while respecting system defaults:

Application logic checks stored preference first. If set to system or not set, the media query applies. If explicitly set to light or dark, that preference takes precedence.

Token systems can support this by generating CSS that checks the preference storage and applies appropriate tokens. JavaScript-based theme switching updates a data attribute that CSS selectors respond to.

Summary

Dark mode token structure requires semantic token layers that map to different primitive values per theme. Effective dark mode goes beyond color inversion to create intentional, accessible, and visually coherent dark experiences. Through careful primitive selection, complete semantic coverage, and appropriate elevation strategies, token systems can support seamless theme switching while maintaining design quality in both modes.

Buoy scans your codebase for design system inconsistencies before they ship

Detect Design Drift Free
← Back to Token Management