Explain Codes LogoExplain Codes Logo

How do I detect dark mode using JavaScript?

javascript
dark-mode
media-query
color-scheme
Alex KataevbyAlex Kataev·Aug 14, 2024
TLDR

Detect dark mode with JavaScript using:

const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; console.log(isDarkMode ? 'Dark mode is on.' : 'Dark mode is off.');

The window.matchMedia() function checks the user's system preferences for dark mode. It returns a boolean: true if dark mode and false otherwise.

Responding to system preference changes

To handle live changes in the system's color scheme, a listener could be beneficial:

const schemeQuery = window.matchMedia('(prefers-color-scheme: dark)'); function updateScheme(e) { let newScheme = e.matches ? "dark" : "light"; console.log(`System color scheme has been updated to ${newScheme}`); // Time to adjust those sunglasses 😎 } schemeQuery.addEventListener('change', updateScheme); // Heads up! For those old buddies like Safari <14, you can use `schemeQuery.addListener(updateScheme)`

Adjusting colors with JavaScript-driven elements

In certain system components like Stripe Elements, we might need to manage the color styling manually using JS:

function configureStripeElementTheme(element, theme) { const styleParams = theme === 'dark' ? { base: { color: '#ffffff' } } : { base: { color: '#000000' } }; // Presto! Stripe is now a chameleon! 🦎🎩 element.update({ style: styleParams }); } // Consider 'cardElement' as your initialized stripe element let prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; configureStripeElementTheme(cardElement, prefersDarkMode ? 'dark' : 'light');

Verifying media-query support

Use window.matchMedia responsibly. First, ensure its support:

if (window.matchMedia) { // It's all systems go! 🚀 } else { // Initiate plan B - fallback or alternative styling strategy }

Handling iOS 13.4 issues

Older iOS versions (specifically iOS 13.4 and below) can be a little finicky with the 'change' event:

const mqList = window.matchMedia('(prefers-color-scheme: dark)'); // This younger cousin knows how to handle those cranky older iOS devices if (typeof mqList.addListener === 'function') { mqList.addListener(updateScheme); } else { mqList.addEventListener('change', updateScheme); }

Tackling diverse color schemes

The world isn't just black and white, it's got shades - handle each color scheme:

switch (schemeQuery.matches) { case 'dark': setAppTheme('dark'); break; case 'light': setAppTheme('light'); break; // More shades, more cases! 🌈 }

Fetching the user's preferred scheme

We can create our own function to dynamically retrieve the user's preferred scheme:

function fetchPreferredScheme() { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; // Practicing my Boolean magic tricks 🎩✨ }

Dark mode detection and accessibility

Visually indicate the chosen theme using a ::after pseudo-element:

body::after { content: " "; display: block; height: 10px; background-color: var(--indicator-color); } // Hey JS, how about a hand in updating --indicator-color?

We can getComputedStyle() to access this pseudo-element:

let style = window.getComputedStyle(document.body, '::after'); console.log(style.backgroundColor);

Dynamically changing image sources

Switch image sources based on the color scheme:

const imgElement = document.querySelector('img'); if (isDarkMode) { imgElement.src = '/path/to/dark/image.png'; // Welcome to the dark side 🌑 } else { imgElement.src = '/path/to/light/image.png'; // Keep shining ✨ }

Fallback for no support

Make sure your website doesn't breakdown for users whose browsers lack color scheme support:

function assignColorScheme() { let supportsThemeChange = window.matchMedia('(prefers-color-scheme)').media !== 'not all'; document.body.className = supportsThemeChange ? fetchPreferredScheme() : 'light'; // Remember, everyone appreciates a little bit of light 💡 }

Checking compatibility

Ensure that 'change' event listeners are functional across different devices, for the sake of a smooth UX:

// This little line will ensure nobody feels left out! schemeQuery.addEventListener('change', () => { console.log('System color scheme change detected'); });