DEV Community

loading...
Cover image for Dark mode with Tailwindcss in Next.js

Dark mode with Tailwindcss in Next.js

enochndika profile image enoch ndika Updated on ・3 min read

Version 2.0 of tailwindcss brings several new features, including dark mode support making it easier than ever to dynamically modify your application when dark mode is enabled.

We will start by creating a new Next.js application

npx create-next-app dark-mode
Enter fullscreen mode Exit fullscreen mode

Tailwindcss installation

yarn add -D tailwindcss postcss autoprefixer
Enter fullscreen mode Exit fullscreen mode

and next-themes that will allow us to switch to dark mode

yarn add next-themes
Enter fullscreen mode Exit fullscreen mode

Create a postcss.config.js file and paste the following configuration of postcss

module.exports = {
  plugins:{
    tailwindcss: {},
    autoprefixer: {
      flexbox: "no-2009",
    }
  }
};

Enter fullscreen mode Exit fullscreen mode

Then create a tailwindcss.config.js file and add the configuration below

module.exports = {
  future: {
    purgeLayersByDefault: true,
  },
  darkMode: "class",
  purge: ["./components/**/*.{js,ts,jsx,tsx}", "./pages/**/*.{js,ts,jsx,tsx}"],
  theme: {},
  variants: {},
  plugins:[]
};
Enter fullscreen mode Exit fullscreen mode

In this configuration, the change of theme will be done with the classes, which will facilitate integration with next-themes.

In the pages directory, create a new file _document.js and add the configuration below

import React from "react";
import Document, { Html, Head, Main, NextScript } from "next/document";

class MyDocument extends Document {
  render() {
    return (
      <Html>
        <Head />
        <body className="bg-white text-black dark:bg-black dark:text-white">
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;
Enter fullscreen mode Exit fullscreen mode

At the body level, we defined the global classNames configuration. When the theme will be by default, the text color will be black and the background color white. When the dark mode will be triggered, the text color will be white and the background color will be black. You can modify them as you want

In the styles directory, replace the content of global.css with this one

@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Then in the _app.js file in the pages directory, we will import ThemeProvider from next-themes and we will also import the global style we defined in global.css in the styles directory.

import "../styles/globals.css";
import { ThemeProvider } from "next-themes";

function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider attribute="class">
      <Component {...pageProps} />
    </ThemeProvider>
  );
}

export default MyApp;
Enter fullscreen mode Exit fullscreen mode

In the index.js file replace the initial content by this one

import Head from "next/head";

export default function Home() {
  return (
    <div className="text-center">
      <Head>
        <title>Dark mode with Tailwind and Next.js</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <h1 className="text:2xl">Dark mode with Tailwind and Next-themes</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

then start the server with

yarn dev

To switch to dark mode we will need useTheme which will be imported from next-themes. useTheme() contains several properties but what will interest us is theme, which returns the active theme and setTheme which allows you to change the theme.

The advantage of this library is that it avoids flash when loading the page on the server side because ThemeProvider automatically injects a script in next/head to update the html element with the correct attributes before loading the rest of the page. This means that the page will not flash under any circumstances.

we will import useTheme in index.js

import { useTheme } from "next-themes"

and we will extract theme and setTheme

const { theme, setTheme } = useTheme();

As we are going to change the client-side theme, we will first check if the component is mounted. we will define a state with useState

const [isMounted, setIsMounted] = useState(false);

and we will set isMounted to true when the component is mounted.

useEffect(() => {
    setIsMounted(true);
  }, []);
Enter fullscreen mode Exit fullscreen mode

then we are going to define a function that will allow to change the theme, checking first if the component is well mounted.

const switchTheme = () => {
    if (isMounted) {
      setTheme(theme === "light" ? "dark" : "light");
    }
};
Enter fullscreen mode Exit fullscreen mode

the full code of index.js

import { useEffect, useState } from "react";
import Head from "next/head";
import { useTheme } from "next-themes";
export default function Home() {
  const [isMounted, setIsMounted] = useState(false);
  const { theme, setTheme } = useTheme();
useEffect(() => {
    setIsMounted(true);
  }, []);
const switchTheme = () => {
    if (isMounted) {
      setTheme(theme === "light" ? "dark" : "light");
    }
  };
return (
    <div className="text-center">
      <Head>
        <title>
          Dark mode with Tailwind and Next.js
        </title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <h1 className="text:2xl">
       Dark mode with Tailwind and Next- themes
      </h1>
      <button onClick={switchTheme}>Change theme</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

You can refresh the page and you won't see any flashes.

Know that you can also implement the dark mode without tailwindcss, just with the next-themes library . it can be implemented with styled-components, emotion or with css classes.

Demo

Source code

Discussion (0)

pic
Editor guide