How do I detect dark mode using JavaScript?

JavascriptMacos Darkmode

Javascript Problem Overview


Windows and macOS now have dark mode.

For CSS I can use:

@media (prefers-dark-interface) { 
  color: white; background: black 
}

But I am using the Stripe Elements API, which puts colors in JavaScript

For example:

const stripeElementStyles = {
  base: {
    color: COLORS.darkGrey,
    fontFamily: `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"`,
    fontSize: '18px',
    fontSmoothing: 'antialiased',
    '::placeholder': {
      color: COLORS.midgrey
    },
    ':-webkit-autofill': {
      color: COLORS.icyWhite
    }
  }
}

How can I detect the OS's preferred color scheme in JavaScript?

Javascript Solutions


Solution 1 - Javascript

if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
    // dark mode
}

To watch for changes:

window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
    const newColorScheme = event.matches ? "dark" : "light";
});

Solution 2 - Javascript

According to MediaQueryList - Web APIs | MDN, addListener is the correct way to listen to the change. addEventListener is not working for me on iOS 13.4.

window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
  console.log(`changed to ${e.matches ? "dark" : "light"} mode`)
});

Solution 3 - Javascript

You can check the CSS Media-Queries directly with JavaScript

> The window.matchMedia() method returns a MediaQueryList object > representing the results of the specified CSS media query string. The > value of the matchMedia() method can be any of the media features of > the CSS @media rule, like min-height, min-width, orientation, etc.

To check if the Media-Query is true, the matches property can be used

// Check to see if Media-Queries are supported
if (window.matchMedia) {
  // Check if the dark-mode Media-Query matches
  if(window.matchMedia('(prefers-color-scheme: dark)').matches){
    // Dark
  } else {
    // Light
  }
} else {
  // Default (when Media-Queries are not supported)
}

To update the color-scheme dynamically based on the user's preference, the following can be used:

function setColorScheme(scheme) {
  switch(scheme){
    case 'dark':
      // Dark
      break;
    case 'light':
      // Light
      break;
    default:
      // Default
      break;
  }
}

function getPreferredColorScheme() {
  if (window.matchMedia) {
    if(window.matchMedia('(prefers-color-scheme: dark)').matches){
      return 'dark';
    } else {
      return 'light';
    }
  }
  return 'light';
}

if(window.matchMedia){
  var colorSchemeQuery = window.matchMedia('(prefers-color-scheme: dark)');
  colorSchemeQuery.addEventListener('change', setColorScheme(getPreferredColorScheme()));
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmikemaccanaView Question on Stackoverflow
Solution 1 - JavascriptMark SzaboView Answer on Stackoverflow
Solution 2 - JavascriptimggView Answer on Stackoverflow
Solution 3 - JavascriptSanBenView Answer on Stackoverflow