Note:
- no dependencies used
- Pure react
STEP 1 : Setting Up The Project
Since our project will be using Tailwind CSS so we start by downloading/cloning the with-tailwindcss example from nextjs Official repository.
npx create-next-app --example with-tailwindcss with-tailwindcss-app
# or
yarn create next-app --example with-tailwindcss with-tailwindcss-app
Then cd into the directory by typing the command
cd with-tailwindcss-app
And start the development server by further typing the command
yarn dev
Open up http://localhost:3000/ in your browser and you must see:

now we are good to go for next step:
STEP 2: Adding The Toggle Button
Modify nav.js file inside of components directory by adding following lines inside the second <ul> tag
<li> <div className=’btn-blue’>Toggle Theme</div></li>
navbar will look like:

we will handle the click later after setting up the theme.
STEP 3: Set up class based dark theme For Tailwind
Open tailwind.config.js and change darkMode from “media” to “class” as:
darkMode: "class", // 'media' or 'class'
Open index.css inside styles directory and add min-height property to body as:
html,body { min-height: 100vh; /* add this line */ @apply bg-gray-50 dark:bg-gray-900;}
STEP 4: Setting up Themeprovider (React Context Api)
- Create a theme Directory in the root.
- Inside theme directory create a file named ThemeContext.js
- Paste the content below inside ThemeContext.js
import React, { createContext, useEffect, useState } from "react";const defaultState = { dark: false, toggleDark: () => {},};const ThemeContext = createContext(defaultState);const ThemeProvider = ({ children }) => {const [dark, setDark] = useState(false);useEffect(() => { const lsDark = localStorage.getItem("dark"); if (lsDark !== null) { setDark(JSON.parse(lsDark)); }}, []);const toggleDark = () => { const d = document.documentElement; const themes = ["light", "dark"]; if (dark) { d.classList.remove(...themes); d.classList.add("light"); } else { d.setAttribute("class", "dark"); } localStorage.setItem("dark", JSON.stringify(!dark)); setDark(!dark);};return ( <ThemeContext.Provider value={{ dark, toggleDark, }}> {children} </ThemeContext.Provider> );};export default ThemeContext;export { ThemeProvider };
- create custom document by creating a file named _document.js inside pages directory and paste the content from below.
import Document, { Head, Html, Main, NextScript } from "next/document";class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
return { ...initialProps };
}render() {
return (
<Html>
<Head>
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
var storageKey = 'dark';
var classNameDark = 'dark';
var classNameLight = 'light';
var d = document.querySelector('html');
function setClassOnDocumentBody(dark) {
d.classList.add(dark ? classNameDark : classNameLight);
d.classList.remove(dark ? classNameLight : classNameDark);
}
var localStorageTheme = null;
try {
localStorageTheme = localStorage.getItem(storageKey);
} catch (err) {}
var localStorageExists = localStorageTheme !== null;
if (localStorageExists) {
localStorageTheme = JSON.parse(localStorageTheme);
}
if (localStorageExists) {
setClassOnDocumentBody(localStorageTheme);
} else {
var isDarkMode = d.classList.contains(classNameDark);
localStorage.setItem(storageKey, JSON.stringify(isDarkMode));
}
})();
`,
}}
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}export default MyDocument;
- wrap the whole app with ThemeProvider by updating the _app.js to same as below
import "../styles/index.css";
import { ThemeProvider } from "../theme.js/ThemeContext";function MyApp({ Component, pageProps }) {
return (
<ThemeProvider>
<Component {...pageProps} />
</ThemeProvider>
);
}export default MyApp;
STEP 5(Final Step): Adding ability to access and change the theme
Now we can access dark and toggleDark using useContext Hook we’ll use it as:
add the below line inside nav component:
const { dark, toggleDark } = useContext(ThemeContext);
and also update the toggle button to:
<li> <div className='btn-blue' onClick={() => toggleDark()}> {dark ? "Light" : "Dark"} Theme </div></li>
Hooray! we just added a dark theme toggle to our nextjs and tailwind app
Here’s another version with Redux.
DEMO: https://nextjs-tailwind-redux-dark.vercel.app/
Github Repo: https://github.com/siddsarkar/nextjs-tailwind-redux-dark