Next.js TailwindCSS Dark Mode Tutorial
Learn how to create a dark mode, light mode, and system mode toggle with Next.js and TailwindCSS.
Step 1: Create Next.js App
npx create-next-app@latest
Step 2: Clean up
/app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
/app/page.tsx
export default function Home() {
return <div>Home</div>;
}
Step 3: Update Tailwind Config
/tailwind.config.ts
import type { Config } from "tailwindcss";
const config: Config = {
// ...
darkMode: "class",
};
export default config;
Step 4: Add dark mode script to root layout
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<script
dangerouslySetInnerHTML={{
__html: `
if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
`,
}}
/>
</head>
<body className={inter.className}>{children}</body>
</html>
);
}
Note: Using Next.js' Script component will cause flash of unstyled content (FOUC). Instead, use a regular script element with dangerouslySetInnerHTML.
Step 5: Create a theme switch component
/components/theme-switch.tsx
"use client";
import { useEffect, useState } from "react";
type Theme = "dark" | "light" | "system" | null;
export default function ThemeSwitch() {
const [theme, setTheme] = useState<Theme>(null);
useEffect(() => {
if (localStorage.getItem("theme") === "dark") {
setTheme("dark");
} else if (localStorage.getItem("theme") === "light") {
setTheme("light");
} else {
setTheme("system");
}
}, []);
function toggleDarkMode() {
if (theme === "system") {
setTheme("dark");
localStorage.setItem("theme", "dark");
document.documentElement.classList.add("dark");
} else if (theme === "dark") {
setTheme("light");
localStorage.setItem("theme", "light");
document.documentElement.classList.remove("dark");
} else if (theme === "light") {
setTheme("system");
localStorage.removeItem("theme");
applySystemTheme();
}
}
function applySystemTheme() {
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
}
return (
<div>
<button className="m-5" onClick={toggleDarkMode}>
{theme === "system" ? "🖥️" : null}
{theme === "dark" ? "🌙" : null}
{theme === "light" ? "☀️" : null}
</button>
</div>
);
}
Step 6: Use the theme switch component
import ThemeSwitch from "@/components/theme-switch";
export default function Home() {
return (
<div className="text-black bg-white dark:text-white dark:bg-black h-screen">
<h1>Home</h1>
<p>Hello, World!</p>
<ThemeSwitch />
</div>
);
}