Dylan Smith

The UX of dark mode toggles

It’s a sunny Friday morning in London and I have the day off work. I walked the dog early, made myself a nice breakfast, and now I’m sat on the sofa with a mug of hot, black coffee, listening to jazz. I’ve decided to work on my website.

I want to add a colour theme toggle. My site already has light and dark modes, and automatically switches based on the visitor’s operating system settings using prefers-color-scheme. But some people — for reasons related to visual impairment, readability, or just aesthetic preference — want to change the theme on a case-by-case basis.

The typical way of handling this is to offer a toggle. For example, clicking a 🌙 icon will switch from light to dark and a ☀️ icon will do the opposite. Pretty straightforward. Articles that describe how to implement these toggles will tell you it’s also good practice to keep the visitor’s preference in localStorage once they’ve clicked a button. This is usually implemented to always take precedence over the OS-level setting, and that’s where it starts to unravel for me.

In theory, yes, learning what people want and giving it to them is good. But I think this persistent approach puts too many assumptions into what that button press actually means. Was the visitor telling you “always give me dark mode no matter what” or were they telling you “give me dark mode for now”?

Let’s say it’s the evening. Your operating system’s auto dark mode hasn’t kicked in yet. You visit a website and find the light background is a little too much. You hit the toggle and get a more readable dark mode. You come back to the same site the next morning and you’re still stuck in dark mode. That stinks.

So now I’m wondering what the best UX is for these things. Here are the options as I see them.

  1. Don’t give the visitor a choice. Serve a theme based on their operating system setting every time. This will sometimes not be what they want and they will be unhappy.
  2. Never remember the visitor’s choice. Serve a theme based on their operating system setting and allow them to override it, but only for that page or visit. They will have to change the theme manually on each subsequent visit if the auto theme is again not what they want.
  3. Always remember the visitor’s choice. Serve a theme based on their operating system setting, allow them to override it, then always default to that theme no matter what. They may be served the “wrong” theme for their context on subsequent visits and have to switch back.
  4. Remember the visitor’s choice for a period of time. Serve a theme based on their operating system setting, allow them to override it, and default to that theme for the next n hours, days, or weeks. This may have a better chance of getting it “right” next time.
  5. Allow the visitor to unset their choice. Serve a theme based on their operating system setting, allow them to override it, default to that choice, but let them switch back to “auto.” Adrian Roselli’s website does this and it seems to account for the downsides and stress cases quite well.
  6. Just ask the visitor. Serve a theme based on their operating system setting, allow them to override it, and ask whether they want that theme all the time or just right now. This introduces a tiny bit of friction — perhaps at the wrong moment — but would have the most accurate results.

I’m going to think about this for a while before I decide what to build.


Am I missing a better approach? What’s the best theme switching experience you’ve seen on the web? Email or tweet at me.

Newer Styling the kbd element Older They grow up so fast