DEV Community

Cover image for How to add a dark mode to your Next.js site
Rémy Beumier
Rémy Beumier

Posted on • Originally published at remybeumier.be

How to add a dark mode to your Next.js site

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

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)