Dark mode
CSS
You need to add styling to the html
element so it applies everywhere.
Use the special root selector for this - see CSS :root
.
Set styling for light and dark cases. e.g.
:root.light-theme {
--background-color-primary: #ffffff;
--background-color-secondary: #eeeeee;
--accent-color: var(--grey);
--text-primary-color: #222;
}
:root.dark-theme {
--background-color-primary: #1e1e1e;
--background-color-secondary: #3f3f3f;
--accent-color: #e4e4e4;
--text-primary-color: #f3f3f3;
}
Then use JS to toggle your class on html
as either light-theme
or dark-theme
value.
Using the root element:
document.documentElement.className = theme;
In this case we don’t have to worry about appending or removing from the class list, as we don’t want other styles on html
and we want to switch between either one or the other class and not both at once.
If you want to append and remove.
if (darkMode) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
You can also use document.body
instead in the CSS and JS, but the root element is preferred.
Get user preference
Read the user’s preference for light or dark mode, as set at the OS or browser level:
const LIGHT_THEME = "light-theme"; // or "light-mode"
const DARK_THEME = "dark-theme";
function browserPreferedTheme() {
const preferDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
return preferDark ? DARK_THEME : LIGHT_THEME;
}
Vue
- Create your own Dark mode toggle component with Vue - useful to read and set the theme.
- DarkMode component through vue-a11y package
See ThemeToggle.vue in my Vue project for a sample toggle, including use of localStorage.
React
- “react dark mode” search with DuckDuckGo.
- Dark mode in React on Code Boost.
Steps:
- Dark mode state hook -
useState
. - Apply the dark class -
useEffect
. - Persist dark mode state -
localStorage
. - Style for dark mode with CSS.
Here is some sample JS:
import { faMoon } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
function App() {
const [isDark, setIsDark] = React.useState(false)
const onClick = () => {
setIsDark(!isDark)
}
React.useEffect(() => {
const ls = window.localStorage.getItem('dark-mode') ?? 'false'
const v = JSON.parse(ls)
setIsDark(v)
}, [])
React.useEffect(() => {
document.documentElement.className = !isDark ? "dark-mode" : ""
window.localStorage.setItem('dark-mode', JSON.stringify(isDark))
},
[isDark]
)
return (
<div className="app">
<div>
<h1 className="title">Dark Mode Demo</h1>
</div>
<button className="app__dark-mode-btn icon level-right" onClick={ onClick }>
<FontAwesomeIcon icon={ faMoon } />
</button>
<p>
My content here
</p>
</div>
)
}
Note that the first effect runs only on mount and unmount.
And the second runs whenever isDark
changes.
After you have the value from local storage initially, you can use the value that is in React’s state. And when the user changes the value, you change the value in state using onClick
and change the value in localStorage using the second effect.