Skip to content
ColorArchive
Dark Mode Color Guide
Search intent: how to choose colors for dark mode design

How to Choose Colors for Dark Mode: A Complete System Design Guide

Dark mode requires fundamentally different color decisions than light mode — not just inverted values, but rethought contrast hierarchies, reduced saturation, and carefully calibrated surface elevations.

Dark ModeColor SystemsUI DesignAccessibilityDesign Tokens
Key points
Dark mode surfaces should use near-black with very subtle warm or cool tints — pure #000000 backgrounds are rarely correct and create harsh halation against light text elements.
Accent colors for dark mode should be lighter and slightly less saturated than their light-mode equivalents, because dark backgrounds amplify perceived saturation.
A proper dark mode token system defines separate values for each semantic role (surface, surface-elevated, text-primary, text-secondary, accent) rather than generating dark values algorithmically from light values.

Start with surfaces, not accents

The foundation of any dark mode palette is the surface hierarchy: the 3-4 near-black values used for background, card, modal, and tooltip levels. A common mistake is starting with accent colors — trying to make your blue button look right on dark — before establishing the neutral foundation. Get the surface hierarchy right first. Most good dark mode systems use a base background around #0f0f0f to #1a1a1a, with each elevation step adding approximately 4-6 points of lightness in HSL. Pure #000000 should be reserved for true-black elements (deep shadows, text on light surfaces), not used as the default background — it creates too harsh a contrast against surface-level elements.

Redefine your accent colors, don't just reuse them

The most common dark mode color mistake is using identical hex values for interactive elements in both modes. A blue at #2563eb — excellent on white — becomes harsh and irradiating on #111111. The dark mode equivalent needs to shift both lightness upward and saturation downward: something like #93c5fd or #60a5fa achieves the same brand recognition with less visual aggression. The rule is: in dark mode, accents should be lighter (because they're illuminating a dark ground) and slightly more muted (because the dark background amplifies the apparent saturation of any hue). Test your proposed dark mode accents against your dark surfaces at 50-70% screen brightness — the real usage environment.

Text color tiers in dark mode

Dark mode text hierarchies are the inverse of light mode: primary text is near-white rather than near-black, and secondary text is a medium gray rather than a lighter gray. A good dark mode text system uses three tiers: primary text at #f5f5f5 to #e8e8e8 (high contrast against dark surfaces), secondary text at #a3a3a3 to #b8b8b8 (sufficient for captions and metadata), and tertiary/disabled at around #6b6b6b (for placeholders and inactive states). Verify each tier against your actual surface values — the contrast ratio requirements don't relax in dark mode. A secondary text color that looks reasonable visually may fail WCAG 4.5:1 against your dark background.

Token architecture for maintainable dark mode

Teams that implement dark mode as a set of color overrides (rather than a proper token system) create maintenance debt that compounds quickly. The correct architecture defines semantic tokens that describe roles, not values: --color-surface-base, --color-text-primary, --color-accent-interactive. Light and dark themes provide different hex values for each token, and all component styles reference only semantic tokens. This means adding dark mode support to a new component requires zero new color decisions — it inherits the theme automatically. CSS custom properties handle this elegantly with a data-theme='dark' attribute on the root element triggering overrides. Design systems in Figma can mirror this with separate light/dark mode variable sets referencing the same semantic names.

Practical next step

Move from the guide into a concrete palette lane

Guides explain the use case. Collections prove the taste. Packs handle the export and implementation layer.

Related guides