When I started listing the features I wanted for my new website, a dark mode toggle was in the top tier list as it's becoming a standard. Even though I'm not a big supporter of dark mode, I know people love it and I was willing to tackle this challenge.
The CSS part
For this feature, we want to use CSS variables. We have a range of variables that will switch according to the color mode.
Here is a snippet example:
main { --text: #000000; --text2: #333333; --bg2: #eeeeee; --bg: #ffffff; }
Here the dark mode style if the .dark
class is applied. We will see the JavaScript later:
main.dark { --text: #ffffff; --text2: #eeeeee; --bg2: #333333; --bg: #000000; }
To finalise the styling part, we use the prefers-color-scheme
check to match users settings.
It needs to be overridden with the .light
class.
This is done this way:
@media (prefers-color-scheme: dark) { main { --text: #ffffff; --text2: #eeeeee; --bg2: #333333; --bg: #000000; } main.light { --text: #000000; --text2: #333333; --bg2: #eeeeee; --bg: #ffffff; } }
The JavaScript and Next.js part
Let's see how we can make this dark mode toggle with useEffect
and useState
.
First, let's create a button that will change the class of our main
element.
When we click on the button we toggle the theme
thanks to React hooks.
import { useState } from 'react'; export default function Main(props) { const [theme, setTheme] = useState(''); const switchTheme = () => { const newTheme = theme === 'light' ? 'dark' : 'light'; setTheme(newTheme); }; return ( <main className={theme}> <button onClick={switchTheme} theme={theme}> {theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} </button> </main> ); }
We have a functional button toggling between dark and light modes. However, it will not save anything and if we reload the page, we will face a light mode whatever we opted for. That's where we use localStorage
.
In order to access the window object and therefore the localStorage, we must ensure the page has fully loaded. We do this with the useEffect(() => {...}, [])
.
We can then check localStorage and if there is an entry for theme
we apply it.
We also update the switchTheme
to save our theme preference in localStorage.
import { useEffect, useState } from 'react'; export default function Main(props) { const [theme, setTheme] = useState(''); useEffect(() => { let localTheme = window.localStorage.getItem('theme'); setTheme(localTheme); }, []); const switchTheme = () => { const newTheme = theme === 'light' ? 'dark' : 'light'; window.localStorage.setItem('theme', newTheme); setTheme(newTheme); }; return ( <main className={theme}> <button onClick={switchTheme} theme={theme}> {theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} </button> </main> ); }
We have a functional dark mode toggle in your Next.js app by now. In case of struggle, check the steps again or click the full solution link below.
TLDR: Codesandbox: Dark mode toggle in Next.js.
I really wanted to share my solution for this, as I found it particularly difficult to make it run, especially with the
localStorage
. I hope it will make your coding easier.
Don't hesitate to ask your questions and add remarks in the comments 🚀
Enjoy coding with Next.js!
Originally posted on https://remybeumier.be
Top comments (0)