220

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?

Uwe Keim
  • 38,279
  • 56
  • 171
  • 280
mikemaccana
  • 94,893
  • 84
  • 350
  • 433
  • 1
    Possible duplicate of [How can I detect if Dark Mode is enabled in macOS Mojave on my website?](https://stackoverflow.com/questions/50730640/how-can-i-detect-if-dark-mode-is-enabled-in-macos-mojave-on-my-website) – mikemaccana May 31 '19 at 11:05
  • 2
    [This second answer](https://stackoverflow.com/questions/50730640/how-can-i-detect-if-dark-mode-is-enabled-in-macos-mojave-on-my-website) isn't marked as accepted, but covers how to use JavaScript with `window.matchMedia` – mikemaccana May 31 '19 at 11:07
  • I couldn't get the `@media (prefers-dark-interface)` media query to work in Chrome 80 (like you mentioned), but `@media (prefers-color-scheme: dark)` did. – Talk Nerdy To Me Mar 31 '20 at 21:08

4 Answers4

411
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";
});
mikemaccana
  • 94,893
  • 84
  • 350
  • 433
Mark Szabo
  • 6,265
  • 3
  • 17
  • 26
  • 57
    I'll just leaver this here: `window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) { console.log('changed!!');})` – Jaromanda X Mar 06 '20 at 03:05
  • 3
    Note that `prefers-color-scheme: dark` does not seem to work in Edge. Not in CSS or Javasript. – VDWWD Jun 07 '20 at 12:08
  • 1
    @VDWWD old Edge or new Edge (Chromium-based)? – Mark Szabo Jun 07 '20 at 13:16
  • The version I have is `Microsoft Edge 44.18362.449.0` with `Microsoft EdgeHTML 18.18363`. But I found out this is an old version. Apparently Windows Update does not automatically updates Edge... Updated manually and now it works. – VDWWD Jun 07 '20 at 14:16
  • Yes, that's the "old" version. As far as I know, the only way to detect dark mode in the EdgeHTML-based Edge is through the Windows APIs which are only available if the user "installs" the app through the Windows Store. I wouldn't bother with this as the Windows feature update 2004 (rolling out right now) replaces the "old" Egde with the new Chromium-based Edge. – Mark Szabo Jun 07 '20 at 19:41
  • This code doesn't work on Xiaomi's mobile default browser (Mi browser), but works in Chrome browser, Please help – Jafaruddeen Ansari Jun 11 '20 at 10:52
  • @JafaruddeenAnsari it seems Xioami browser does not support this standard browser API. There is nothing you can do most likely. Maybe Xiaomi has a non-standard proprietary API, but I doubt that. – Mark Szabo Jun 12 '20 at 10:05
  • Just teste with Chrome 86.0.4240.75 and Win 10 1909 and runs perfect$ – ZR87 Oct 12 '20 at 19:37
  • @MarkSzabo can i use this scenario for all browsers like safari or firefox? or i've to check another property instead `(prefers-color-scheme: dark)` for them? – Martin Rützy Nov 02 '21 at 09:35
  • I am using this in Cordova iOS App (WKWebView). works perfectly! – Rohit Singh Nov 18 '21 at 17:19
  • I am using Edge 100.0.1185.44 (Official Build) (64-bit) on windows 10 and the above does not work. The above code works fine on Chrome and Firefox. Any suggestions? – AshD Apr 21 '22 at 16:10
16

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`)
});
imgg
  • 391
  • 5
  • 12
  • 4
    Also from MDN - This is basically an alias for EventTarget.addEventListener(), for backwards compatibility purposes. – Gerrit0 Jun 21 '20 at 22:08
  • 3
    Just to quote the mentioned MDN, as I was confused and looked it up: " `addListener()` Adds to the MediaQueryList a callback which is invoked whenever the media query status—whether or not the document matches the media queries in the list—changes. This method exists primarily for backward compatibility; **if possible**, you should instead use `addEventListener()` to watch for the change event." – BananaAcid Apr 10 '21 at 03:50
  • According to MDN it's deprecated – khaki May 26 '22 at 20:58
15

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()));
}
A Pars
  • 1,714
  • 2
  • 21
  • 28
SanBen
  • 1,789
  • 20
  • 30
-1

You need color-mode If you develop your app using nuxt.

Aborn Jiang
  • 807
  • 10
  • 8