Simple setup for dark and light theme toggle in NextJS

02/15/2023

reactjs, nextjs, tailwindcss, next-themes

Simple setup for dark and light theme toggle in NextJS

Are you looking to implement a dark and light theme on your NextJS website with a toggle switch? I will show you a super simple implementation, that will take you about 5 minutes to implement.

What will we be using?

As for this project we will be using a package named next-themes and the default NextJS CSS Modules, but great news! The library we will be using next-themes works well with Tailwind CSS as well, if that is what you’re looking for. It will provide us with an easy solution to manage your website’s theme.

Getting started

First we will need to install the necessary dependencies, for this we are assuming you already have Tailwind CSS installed if that is the route you are going. So let's install the main library we need which is next-themes by running the command:

npm i next-themes

Setting up next-themes

Inside your _app.js or _app.tsx (depending on if you are using TypeScript in your project) we will wrap the Component with a ThemeProvider from next-themes.

If you are using Tailwind CSS then you will also have to pass attribute="class" to the ThemeProvider else it is not necessary.

This is what our _app.tsx file should look like after the change:

import type { AppProps } from 'next/app'
import { ThemeProvider } from "next-themes";
 
export default function App({ Component, pageProps }: AppProps) {
  return (
      <ThemeProvider>
          <Component {...pageProps} />
      </ThemeProvider>
  );
}

If using Tailwind CSS

If you are using Tailwind CSS then this is an extra step where you have to add a property to your config file tailwindcss.config.js. We need to tell Tailwind that we’re going to be changing the theme manually instead of purely relying on the users system preference. In order to do that we need to add the darkMore: "class" property to the config as such:

module.exports = {
  darkMode: "class",
  purge: [
    "./components/**/*.{js,ts,jsx,tsx}",
    "./pages/**/*.{js,ts,jsx,tsx}"
  ],
  theme: {},
  variants: {},
  plugins:[]
};

Default styles on globals.css

If you are using Tailwind CSS then you can skip this step, because then you are basically ready to use dark: on classes to use Dark Mode.

If you are not using Tailwind CSS let’s set up some default styles in our globals.css file. Here we can set our default variables and what they should be in case the theme is set to “dark”:

:root {
    --background: #FFFFFF;
    --foreground: #000000;
}
 
[data-theme='dark'] {
    --background: #161B26;
    --foreground: white;
}

Theme based on system preference

We can also use the prefers-color-scheme media feature to detect if a user has a dark colour theme set on their operating system and set the websites default theme to be dark:

@media (prefers-color-scheme: dark) {
    html {
        color-scheme: dark;
    }
}

Creating a theme toggle button

We have everything set up. Now we can simply use next-themes useTheme() hook to find out the current theme on our website as well as to set another theme as active.

Here is an example theme toggle component using next-themes to toggle the theme between light and dark:

import {useTheme} from "next-themes";
import {useEffect, useState} from "react";
 
const ThemeToggle = () => {
    const { theme, setTheme } = useTheme();
    const [mounted, setMounted] = useState(false);
 
    useEffect(() => {
        setMounted(true);
    }, []);
 
    if (!mounted) return null;
 
    return (
        <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
            Toggle theme
        </button>
    );
}
 
export default ThemeToggle;

Then you can simply use this component inside your navigation, header or wherever you prefer to have a theme toggle button.

We are done, congratulations you have your light and dark themes implemented!

🎉