
Choosing a Colour Palette That Survives Dark Mode
Every product I have worked on in the last two years has shipped with a dark theme, and every one of them started the same way: someone took the light palette, flipped the greys and called it done. It looks fine in the first screenshot. Then the charts arrive, the status colours glow like neon signs, and the brand blue that felt calm on white starts vibrating on black.
The problem is that colour perception is not symmetrical. A saturated colour on a dark background appears brighter and larger than the same colour on white. Shadows, which do most of the work of separating layers in a light interface, almost disappear in a dark one. So a dark theme is not an inversion. It is a second design that happens to share the same structure.
Start from roles, not colours
The fix is to stop naming colours by what they look like and start naming them by what they do. Instead of blue-500 and grey-100, the interface asks for primary, surface, border and muted-text. Each theme then decides what those roles mean.
- Surfaces step up in lightness as they get closer to the user in dark mode, instead of relying on shadows.
- Primary is usually a little lighter and a little less saturated in dark mode, so it reads at the same weight.
- Text is never pure white on pure black. A soft off-white keeps long passages comfortable.
- Borders carry more of the layout in dark mode, so they deserve their own token rather than a reused grey.
Once every component uses roles, adding a theme is a matter of filling in a table. It also makes contrast testing honest: you check each pair of roles once per theme, instead of hunting through hundreds of hard-coded values.
“If a colour only works in one theme, it was never a design decision. It was an accident that happened to look good.”
Studio notes
A good test before shipping is to put both themes side by side and squint. The hierarchy should be identical: the same things should jump out first, the same things should recede. When they do, the palette has survived.




Leave a Comment