user-prefers-theme

This small library manages a class on the <body> element, of the form user-prefers-theme-(light|dark). It reflects the user's system theme setting, or their preference for the current origin. A callback can be registered so that you can update a theme UI on your page when either preference is updated.

How might you use it?

Some design notes…

The API can be found below.

Try it out

Here's a basic UI. You can manually switch between light and dark mode at system level and then check this page's appearance and the readout below.

Demo buttons and current theme

Current theme:

Tests

Most of the tests are automatic, with several running when this page loads. Some of them might cause a flash in your browser, so they must be instigated manually. Finally, some tests need your help in changing the system theme setting. Test results can be found in the console.

Tests that may cause flashes in your browser

Note: the tests could cause flashes in any browser, but I have observed a flash in Internet Explorer only so far.

Tested in browsers

Test notes:

Usage and API

Load user-prefers-theme.js via a script tag—either in the <head> element with the defer attribute set (recommended, as it allows the script to be downloaded in parallel), or at the end of your document's <body>. It will start managing the class applied to the <body> element.

The following functions are exported.

window.userPrefersThemeListener(callback)

Register a callback that will be passed either the system theme setting, or the user's preference for the current origin.

The callback will be called immediately, and whenever the system or user preference changes (the latter takes precedence, as described below). It is passed the string 'light' or 'dark'.

Calling this again replaces any previously-registered callback.

window.userPrefersTheme('light'|'dark')

Switch to the given theme, and save the user's preference for it (on this origin). The preference is persisted indefinitely, and stops the automatic tracking of the system theme setting.

Values other than 'light' or 'dark' will cause an error to be thrown.

If the theme requested is the same as the current one, the user's preference will be saved, but the callback won't be run.

window.userPrefersThemeNeither()

Used to remove an existing preference for light or dark theme on this origin, and return to tracking the system setting.

If the current system setting and previously user-preferred theme differ, then the class on <body> will be updated and the callback run.

Implementation

Development

user-prefers-theme repository on GitHub