JAVASCRIPT
Implement Dark Mode with useDarkMode Hook
A custom React hook to effortlessly add dark mode functionality to your application, persisting user preference across sessions using localStorage and system preferences.
import { useState, useEffect } from 'react';
const prefersDarkMode = () =>
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
const useDarkMode = () => {
const [isDarkMode, setIsDarkMode] = useState(() => {
try {
const storedValue = localStorage.getItem('darkMode');
return storedValue ? JSON.parse(storedValue) : prefersDarkMode();
} catch (error) {
console.error("Error reading from localStorage:", error);
return prefersDarkMode();
}
});
useEffect(() => {
try {
localStorage.setItem('darkMode', JSON.stringify(isDarkMode));
} catch (error) {
console.error("Error writing to localStorage:", error);
}
if (isDarkMode) {
document.body.classList.add('dark-mode');
document.body.classList.remove('light-mode');
} else {
document.body.classList.add('light-mode');
document.body.classList.remove('dark-mode');
}
}, [isDarkMode]);
return [isDarkMode, setIsDarkMode];
};
export default useDarkMode;
/*
// Example CSS (in a global stylesheet or component-scoped styles):
// body.light-mode { background-color: #fff; color: #333; }
// body.dark-mode { background-color: #333; color: #fff; }
// Example Usage:
function ThemeSwitcher() {
const [isDarkMode, setIsDarkMode] = useDarkMode();
const toggleMode = () => {
setIsDarkMode(prevMode => !prevMode);
};
return (
<div>
<p>Current theme: {isDarkMode ? 'Dark' : 'Light'}</p>
<button onClick={toggleMode}>
Toggle to {isDarkMode ? 'Light Mode' : 'Dark Mode'}
</button>
<p>This paragraph will change color based on the theme.</p>
</div>
);
}
*/
How it works: The `useDarkMode` hook provides an elegant solution for implementing dark mode functionality in React applications. It manages the `isDarkMode` state, which is initialized based on user preference stored in `localStorage` or the system's `prefers-color-scheme` setting. An `useEffect` hook ensures that `localStorage` is updated whenever `isDarkMode` changes, and critically, it applies or removes `dark-mode` (or `light-mode`) classes to the `document.body`, allowing CSS to dynamically adjust the theme. The hook returns the current mode and a setter function, similar to `useState`, for easy toggling.