Detecting Dark Mode in JavaScript involves checking the user's preferred color scheme. For this we'll use the window.matchMedia
method to achieve this.
The window.matchMedia
API is a JavaScript utility for checking if the document matches a particular media query.
if (window.matchMedia) {
// Supports this feature, use it safely!
}
Next, we’ll need to provide a query to our matchMedia
and pass in the prefers-color-scheme
with a corresponding value (light
or dark
):
if (window.matchMedia) {
const query = window.matchMedia('prefers-color-scheme: dark');
}
Our query
value here would look something like this (if the user had set the system/device preference of Dark Mode):
MediaQueryList { media: '(prefers-color-scheme: dark)', matches: true, onchange: null }
You can see here there’s a MediaQueryList
instance that holds a matches
property. When true, the user prefers Dark Mode!
So, what now? This is where you’d toggle a class perhaps on your <body>
tag.
Wrapping things into a function could condensed to something as simple as this:
const isDarkMode = () =>
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
But, what about subscribing to changes to our Dark Mode, assuming the user decides to change their preferences or the time of day toggles the device to dark at night time?
Well, did you spot the onchange: null
property on our MediaQueryList
instance? Good!
We could either use query.onchange
directly, or use an addEventListener
(which would definitely be the preferred method as we can create multiple listeners anywhere in our applications):
const runColorMode = (fn) => {
if (!window.matchMedia) {
return;
}
const query = window.matchMedia('(prefers-color-scheme: dark)');
fn(query.matches);
query.addEventListener('change', (event) => fn(event.matches));
}
runColorMode((isDarkMode) => {
if (isDarkMode) {
document.body.classList.add('dark-mode');
} else {
document.body.classList.remove('dark-mode');
}
})
Here I’ve included an example of adding an “active” class for Dark Mode activation, and also demonstrated how to get notified on changes.
The change
event from the query
will fire when the user toggles their Dark Mode system preference, and gives us a nice event.matches
property that mirrors the matches
property found on the MediaQueryList
object.
So that’s it, you can do so much more with this - save the preferences in window.localStorage
and much more.
There you have it, enjoy and happy Dark Mode-ing!.