4 min readby Milap Magar
Design tokens that survive a theme toggle
Dark mode isn't inverted light mode. The token structure that made this site's toggle painless: semantic names, values swapped per theme, and components that never know which theme they're in.
This site has a dark theme, a light theme, a device preference, and a manual toggle that overrides it. The reason that isn't a maintenance nightmare is one rule: components reference token names, never colours, and only the token values change per theme.
Name tokens by role, not by appearance. --ink is the page ground and --white is the primary text — and yes, in light mode '--ink' resolves to white and '--white' to near-black. That feels wrong for about a day, and then it becomes the whole point: the component says 'page ground' and 'primary text', and the theme decides what those mean.
Resolution order does the heavy lifting: base dark values on the root class, a prefers-color-scheme media query for device-light, and data-theme attributes set by the toggle that beat both. The anti-flash script sets the attribute before first paint, so nobody ever sees the wrong theme for a frame.
The last piece is designing the second theme instead of generating it. Glows that look electric on charcoal look like smudges on white, so the dark theme gets green glow shadows and the light theme gets soft elevation instead. Same tokens, different values — different design, one system.