Skip to content
· 6 MIN READ · DARK MODE · LIGHT MODE · WEBDEV · CSS · FRONTEND DEVELOPMENT · REACT · NEXT.JS · ACCESSIBILITY · UX

Dark or Light Mode? Default to Auto

I built a theme switch because bright websites ruin my mood. Then my own site did it to someone else.

My laptop is in dark mode. I open a website. It's white.

Now I'm squinting, hunting for a toggle, and honestly a bit annoyed before I've read a single word. It hurts my eyes, and it hurts my mood.

So I built a three-way theme switcher for my new site: Dark, Light and Auto. Auto just does whatever your system is already doing.

Then, while writing this post, I found out what my own site does for a first-time visitor whose system is on light mode. It gives them a dark site. Exactly the thing I hate, the other way round.

Not on purpose. One word in a config file.

So this is the post I wish I'd read before I built it: how Auto actually works, the default I got wrong, the four ways I've seen dark mode go wrong, and when you shouldn't bother at all.

A cartoon fish with red, smoking eyes, grimacing in pain

When your laptop's in dark mode and the website didn't get the memo.

How Auto works: your laptop already answered the question

Your computer already knows whether it's in dark or light mode. The browser passes that on, and CSS can ask for it with prefers-color-scheme:

:root {
  --bg: #ffffff;
  --text: #111111;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #121212;
    --text: #e6e6e6;
  }
}

body {
  background: var(--bg);
  color: var(--text);
}

Set your colours once as variables, swap them in one place when the answer is "dark", and everything that uses them follows.

That's the whole of Auto. No JavaScript, no toggle, nothing to save. If my laptop is on dark mode, the page is dark before I've touched a thing.

Dark, Light, Auto: and Auto goes first

Auto on its own isn't enough. Some people want dark mode at noon, or light mode at midnight, whatever their laptop says. So you add a switch.

The switch on my current site has two options. Click it and it flips between dark and light. The problem is that the moment someone clicks it, Auto is gone. There's no way back to "just follow my system". I never noticed until I went digging for this post.

That's why the new one has three: Dark, Light and Auto. (And yes, Light's keyboard shortcut is W, because LinkedIn had already taken L.)

But three options only help once someone clicks one. Before that, a first-time visitor gets whatever you set as the default. I use next-themes, a small library that runs the theme switch in React and Next.js, and this is where my one word lived:

<ThemeProvider
  attribute="data-theme"
  defaultTheme="system" // mine said "dark"
  enableSystem
>

defaultTheme is what someone gets before they've chosen anything. Mine said dark. It's fixed now.

Not using next-themes? Same rule: if someone hasn't chosen yet, ask prefers-color-scheme instead of guessing.

One thing changes in the CSS once there's a switch. The media query only listens to the laptop, so a button can't overrule it. That attribute="data-theme" line is the answer: whatever someone picks gets written onto the page as data-theme="dark" or "light", and the CSS reads that label instead:

[data-theme="dark"] {
  --bg: #121212;
  --text: #e6e6e6;
}

Auto just means "write down whatever the laptop says".

Two identical cartoon Spider-Men pointing at each other

When the site that ignores your settings turns out to be yours.

Four ways dark mode goes wrong: I've seen all of them

I've run into every one of these as a user. Each one has a small fix.

The disappearing logo. A black logo on a dark background just vanishes. Your brand, gone. If the logo is an SVG, give it currentColor:

<svg viewBox="0 0 100 24" aria-label="Logo">
  <path fill="currentColor" d="…" />
</svg>

currentColor means "use the text colour here". Dark mode has light text, so the logo turns light too.

Pure black with pure white text. #000 behind #fff is the most contrast you can get, and that's the problem. On a phone at night the letters seem to buzz. That's why the first code block uses #121212 and #e6e6e6. Still dark, still readable, easier on the eyes.

Grey text you have to squint at. The opposite problem. A soft grey looks classy for secondary text in light mode. Drop it onto dark grey and it disappears. The rule of thumb is a contrast ratio of at least 4.5:1 for body text. You don't have to work it out yourself: inspect the text in Chrome DevTools, click the colour swatch, and it shows you the ratio.

The forgotten choice. You pick dark. You open the next page, or come back tomorrow, and it's light again. Save the choice and read it back:

localStorage.setItem('theme', 'dark');
const saved = localStorage.getItem('theme');

localStorage is a small bit of storage in the browser that survives refreshes and tomorrow. If you're on next-themes, it already does this for you.

The old version of this post said "don't forget to save the preference in local storage." It was the most useful line in it.

Homer Simpson slowly backing into a hedge until he disappears

When your black logo meets dark mode.

When not to bother: dark mode isn't compulsory

Not every website needs dark mode. Only add it if your users would actually use it.

I built a site for a construction company with no dark mode at all. If I'm honest, that wasn't a decision about users. I built it in WordPress, I didn't know my way around WordPress like I know React, so I left it as it was.

But the people visiting that site are homeowners looking for a builder. They wouldn't have used it. The rule held, even if I got there by accident.

So, which team are you on?

Wrong question. The right answer is whichever team your reader's laptop is already on.

Default to Auto. Give people Dark and Light for when they want to overrule it. Skip pure black, check your greys, let your logo follow the text, and remember what people picked. And if your users wouldn't use dark mode at all, skip it. That's perfectly okay.

What does your site show a first-time visitor whose laptop is set to the opposite mode? Go and check. Mine was wrong, and I built the switch.