Supporting & detecting dark mode in the browser

Jan 7, 2020
Last update: Sep 22, 2020
~ 2 min

How do you detect if a user of your website has a preference for light or dark theme? Or maybe has not chosen at all?

We will look at a few ways how to detect and handle dark modes in 2020:

  1. Pure CSS
  2. JS
  3. React
Photo by davisco on Unsplash

Pure CSS

First lets have a look how we can do this using only CSS. There is a new css media query that is supported by almost any browser right now.
prefers-color-theme

Example Time
.box { 
    background: #eee;
}

@media (prefers-color-scheme: dark) {
    .box { 
        background: #000;
    }
}

@media (prefers-color-scheme: light) {
    .box { 
        background: #fff;
    }
}

Just like we use media queries for device width we can easily target specific CSS in case the user has a specific preference.

For completeness, if the user has no preference you can use the media query @media (prefers-color-scheme: no-preference).

JS

Simple

So how do we do the same thing in JS? There is a little helper called window.matchMedia (also widely supported) wich takes a media query and tells us if the media query is true of false.

Example
const isDark = window.matchMedia('(prefers-color-scheme: dark)')
isDark.matched // true or false

That simple.

Reactive

If we want to go reactive, the matchMedia function also allows us to set a listener, so every time the setting changes, we get notified and can act accordingly.

Example
const isDark = window.matchMedia('(prefers-color-scheme: dark)')
isDark.addListener((event: MediaQueryListEvent) => {
  event.matches // true or false
})

React

And of course react. We love it, we use it. So I made a little library because all the libs I found for react did not include typescript typing!! 🤕

Of course it comes with hooks 🎣.

yarn add use-light-switch

useLightSwitch()

This is the basic usage.

import { Mode, useLightSwitch } from 'use-light-switch'


const Simple: React.FC = () => {
    const mode = useLightSwitch()

    if (mode === Mode.Dark) ...

    return ...
}

useModeSelector()

This is the more useful one IMO.

import React from 'react'
import ReactDOM from 'react-dom'
import { useModeSelector } from 'use-light-switch'

const App: React.FC = () => {
    const selected = useModeSelector({
        light: { color: 'green', name: 'Light' },
        dark: { color: 'red', name: 'Dark' },
        unset: { color: 'blue', name: 'Unset' },
    })

    return <div>
        <p>Try switching your dark mode in macOS or Windows</p>
        <div style={{
            padding: '1em 2em',
            backgroundColor: selected.color
        }}>
            {selected.name}
        </div>
    </div>
}

ReactDOM.render(<App />, window.document.getElementById('root'))