Write JavaScript like a pro. Javascript Icon

Follow the ultimate JavaScript roadmap.

Detecting Dark Mode in JavaScript

Detect Dark Mode in JavaScript and learn how to watch for changes, so you can update your styles accordingly.

For this, we’ll need to use the window.matchMedia API.

The window.matchMedia API is a JavaScript utility for checking if the document matches a particular media query.

We’re used to using this for things like responsive web, but with the introduction of Dark Mode we have more at our disposal.

Want to detect Dark Mode in your CSS Styles as well? Read “Applying Dark Mode Styles in CSS” after.

Feature detection is paramount, as not all browsers support the window.matchMedia API.

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.

🏆 P.S. check out my latest JavaScript courses if you’re serious about taking your skills to the top.

There you have it, enjoy and happy Dark Mode-ing!.

Learn JavaScript the right way.

The most complete guide to learning JavaScript ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover