Dark mode is a token problem, not a color problem
Switching themes cleanly is mostly about naming colors by role instead of by value.
Hammad Iqbal
Software Engineer
Adding dark mode late in a project usually means hunting through hundreds of hard-coded colors. Adding it early, with named tokens, takes an afternoon. The difference is whether colors are described by what they are for or by what they look like.
- Name colors by role, such as surface, text, and border.
- Swap the values per theme in one place.
- Test contrast in both themes, not just the one you built first.
Roles, not values
A token called gray-100 describes a color. A token called surface describes a job. When the theme changes, the job stays the same and only the value behind it moves, so no component needs to be edited.
One place to swap
Define the tokens as CSS variables on the root and redefine them for the dark theme. Components read the variables and never know which theme is active. Respect the system preference by default and let users override it.
Contrast and the in-between states
Dark themes are not just inverted light ones. Shadows get weaker, borders matter more, and saturated colors can vibrate on a dark background. Check text contrast, focus rings, and disabled states in both themes before shipping.
Define colors by role, swap them in one place, and check both themes for contrast.
Have a project this kind of thinking applies to?
Tell me what you're building — I read every message myself.