Start with roles instead of inverted swatches
Automatic inversion changes every channel mechanically, but interface meaning is not encoded in channel values. A white page may become black, yet elevated cards, separators, disabled controls, illustrations, and status colors can lose their intended relationships. Define semantic roles first: canvas, raised surface, primary text, secondary text, border, accent, danger, and focus. Assign dark-theme values to those roles independently. This keeps component code stable while letting the theme preserve visual hierarchy. It also makes review concrete because each token has a documented job rather than a vague name such as dark-gray-3.
- Use at least two surface tokens so cards and overlays can separate from the page without depending on shadows alone.
- Keep primary and secondary text as distinct roles, then measure each role against every surface on which it appears.
- Reserve accent colors for actions and emphasis; do not make every decorative element compete with interactive controls.
- Name tokens by purpose, such as text-muted or border-subtle, so later value changes do not require component rewrites.
Build the surface ladder deliberately
Dark surfaces need enough separation to communicate containment, but large luminance jumps can make the page look striped and increase visual noise. Begin with the darkest canvas, then introduce slightly lighter values for cards, menus, and dialogs. A border can reinforce an edge when the adjacent fills are close. Shadows remain possible, although they are less visible against a dark canvas and should not be the only boundary signal. Test nested combinations directly: a dialog over a page, a menu over a card, and an input inside a panel. The relevant comparison is always between neighboring rendered colors.
| Role | Example | What to verify |
|---|---|---|
| Canvas | #101318 | Primary text, links, and persistent navigation |
| Raised surface | #181C22 | Card boundary and nested controls |
| Border | #46505E | Visible edge against both adjacent fills |
| Overlay | #20252D | Dialog content and focus indicator |
Create explicit tokens and declare the color scheme
Centralized tokens make dark-mode behavior inspectable. In this explicitly dark example, color-scheme: dark tells supporting user agents to render form controls and other system-provided UI for a dark scheme, while custom properties hold the application choices. Declaring only dark is deliberate here because the shown tokens do not include light-theme overrides. The declaration does not prove accessibility and does not replace component testing. The sample values form a starting set, not a universal palette: typography, font weight, antialiasing, surrounding colors, and actual state combinations affect the result. The code block remains identical across documentation locales.
:root {
color-scheme: dark;
--surface-0: #101318;
--surface-1: #181C22;
--text-primary: #F2F4F7;
--text-muted: #B8C0CC;
--border: #46505E;
--accent: #8AB4F8;
--focus: #FFD166;
}Measure text, controls, and focus separately
WCAG contrast requirements describe particular content and states, not a single score for an entire palette. Ordinary text generally needs a contrast ratio of at least 4.5:1 under Success Criterion 1.4.3, while qualifying large text has a 3:1 threshold. Essential graphical objects and visual information required to identify user-interface components are addressed by non-text contrast. Focus appearance has its own requirements in WCAG 2.2. Measure the foreground against the color immediately behind it, including hover, pressed, selected, disabled, validation, and overlay states. Do not average several backgrounds or assume a token passes everywhere.
- Measure primary and muted text against every surface token that can host them, rather than checking only the page canvas.
- Check icons and component boundaries when they are required to identify the control or understand its current state.
- Evaluate focus indicators against the colors they touch in the focused state, including both the component and surrounding surface.
- Recalculate contrast after opacity or blending because the resulting composite color, not the source token, is what users see.
- Test selected, hover, active, error, and disabled states independently; one passing default state cannot represent all of them.
Control accents without flattening their meaning
A saturated accent that worked on white may vibrate visually on a near-black surface or fail when used as text. Treat fill, text, icon, and border uses as different pairings. A lighter accent can improve contrast for links on dark surfaces, while a darker foreground may be required on an accent-filled button. Status meaning must also appear through text, icons, placement, or patterns when color is not the only permitted cue. Keep decorative aurora effects behind content and verify the actual pixels beneath text. Gradients require testing at their least favorable point, not only at the endpoints.
Review the theme as a system
Finish with a component matrix rather than a screenshot review. Render representative headings, body copy, links, buttons, fields, tables, banners, charts, menus, and dialogs on every supported surface. Navigate with a keyboard and inspect focus at normal zoom and with browser zoom increased. Exercise forced-colors or high-contrast settings where supported, and verify that native semantics still communicate state. Automated contrast checks are useful for stable pairs, but overlays, gradients, antialiasing, and dynamic states still need human inspection. Record tested combinations beside the tokens so future palette changes can rerun the same evidence.
- Inventory every semantic token and list the surfaces or components where it is allowed to appear.
- Generate a state matrix for default, hover, focus, active, selected, disabled, and validation presentations.
- Run deterministic contrast calculations for solid color pairs and keep the measured values with the design review.
- Perform keyboard, zoom, and real-device checks before release, then repeat them whenever shared theme tokens change.
Primary sources
The factual claims in this article are checked against these published specifications.