Using Users' Preferences for Dark Mode
- CSS Media Query
- JavaScript - One time check
- JavaScript / TypeScript - Watch for color scheme preference change
- React Hook
- References
Dark mode is available and used pretty much everywhere now. Most operating systems allow users to set their preference between light and dark mode and this can be detected in the browser.
The following are notes on how to detect users' preferences in CSS and JavaScript / TypeScript.
CSS Media Query
For CSS, all that is required is to write your styles by default in light mode and then wrap your dark mode changes in the @media (prefers-color-scheme: dark)
media query (Note: you can also write your styles for dark mode by default and change the query to match light
instead to do the inverse).
/** Default for light mode */
body {
background-color: #1f1f1f;
color: #efefef;
}
@media (prefers-color-scheme: dark) {
/** Make background dark and text light in dark mode */
body {
background-color: #1f1f1f;
color: #efefef;
}
}
JavaScript - One time check
if (
window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches
) {
// Dark mode
} else {
// Light mode
}
JavaScript / TypeScript - Watch for color scheme preference change
window.matchMedia &&
window
.matchMedia('(prefers-color-scheme: dark)')
.addEventListener('change', (evt: MediaQueryListEvent) => {
// This event fires whenever the client changes their preferred color scheme
if (evt.matches) {
// Dark Mode
} else {
// Light mode
}
});
React Hook
File:
usePrefersDarkMode.ts
import { useEffect, useState } from "react";
export default function usePrefersDarkMode() {
const [prefersDarkMode, setPrefersDarkMode] = useState<boolean>(
window.matchMedia("(prefers-color-scheme: dark)").matches
);
useEffect(() => {
const onPreferenceChange = (evt: MediaQueryListEvent) => {
setPrefersDarkMode(evt.matches);
};
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
mediaQuery.addEventListener("change", onPreferenceChange);
return () => {
// Remove listener on unmount
mediaQuery.removeEventListener("change", onPreferenceChange);
};
}, []);
return prefersDarkMode;
}