Dark Mode Token Structure
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
- Not all primitive colors work well in both themes; palettes may need theme-specific additions
- Semantic token coverage must be complete for both themes
- Contrast ratios must be validated separately for each theme
- Elevation and shadow approaches may differ between themes
- Some colors (error red, success green) may need different shades per theme
- Images and illustrations may need theme-aware variants
- System preference detection should inform default theme
- Theme persistence across sessions requires storage strategy
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