Skip to content
Back to Blog
Dark ModeUIDesign

Build a Dark Mode Palette with Tested Color Roles

Work through a dark canvas, surface, body text and action color, then check their actual pairings before exporting.

March 18, 2026· 2 min read·Color Match

Updated : Rechecked technical claims, replaced unsupported generalizations, and added reproducible examples and source links.

Build dark mode by assigning roles rather than inverting every light-mode value. The example here is a reading interface: a dark canvas contains raised cards, body text and a single primary action. These are editable design choices, not a claim that one dark palette suits every reader.

Choose a canvas and surface

Start with #111827 for the canvas and #1F2937 for cards. Their small lightness difference suggests grouping; it is insufficient evidence that a field or essential boundary is identifiable. Where that boundary matters, add a border and measure it against the adjacent surface. Pure black is also a valid design choice; there is no universal rule forbidding it.

Measure text on each surface

A reproducible text and background example.

Same pair, larger text.

##F9FAFB / ##111827

Body text on the page canvas.

1.000000:1 WCAG contrast; 0.0000 Lc APCA.

Normal-text AA: Fail. Large-text AA: Fail. Labels apply to text contrast only.

Reproduce this pair and try a fix

A reproducible text and background example.

Same pair, larger text.

##9CA3AF / ##1F2937

Secondary text on a card, measured independently.

1.000000:1 WCAG contrast; 0.0000 Lc APCA.

Normal-text AA: Fail. Large-text AA: Fail. Labels apply to text contrast only.

Reproduce this pair and try a fix

Try longer paragraphs at the actual font size. Dim secondary text can disappear when its card changes color. Our example keeps opacity at 1 so the input pair matches the rendered colors. An opacity setting would require recalculating the composite color.

Use a separate action token

A reproducible text and background example.

Same pair, larger text.

##111827 / ##93C5FD

Dark text on a pale blue action button.

1.000000:1 WCAG contrast; 0.0000 Lc APCA.

Normal-text AA: Fail. Large-text AA: Fail. Labels apply to text contrast only.

Reproduce this pair and try a fix
:root[data-theme="dark"] {
  --surface-canvas: #111827;
  --surface-card: #1F2937;
  --text-primary: #F9FAFB;
  --text-secondary: #9CA3AF;
  --action: #93C5FD;
  --on-action: #111827;
}

Validate the transition

In your app, test switching themes while a menu, error message or dialog is open. Retest hover and focus colors; an inherited light-theme token is easy to miss. Offer a usable theme choice rather than assuming everyone prefers the same brightness.

Open this dark palette in Studio to inspect the pair matrix and export its values. Assign the role aliases above in your stylesheet; an automatically generated scale does not carry those decisions for you.

Sources and further reading

Editorial and correction policy

Try it yourself

Try this palette in Studio

Edit the dark surface, reading text, muted text and accent. Recheck each pair on the surface where it appears.

Edit this palette

Color Match

Color Match publishes and maintains practical color guides alongside its tools. Check the sources and revision notes on each updated guide, and report reproducible issues through our contact page.

More about Color Match

Related Articles