In my journey to incorporate the dark mode feature into Next.js, I vividly recall my initial attempt using a familiar approach from React—the useContext
hook. Unfortunately, this method proved unsuccessful, leading me to an extensive exploration marked by numerous hours of trial and error. Despite facing challenges and encountering errors, persistence ultimately paid off as I uncovered the correct path to seamlessly integrate dark mode functionality into Next.js.
In this post, we'll walk through how to implement dark mode in a Next.js application using Tailwind CSS and the next-themes library.
Setting Up
To commence, ensure you have a Next.js application with Tailwind CSS configured. Fortunately, simplifying this process is the npx create-next-app@latest
command, which conveniently sets up a Next.js app pre-configured with Tailwind. Execute this command to effortlessly initialize and set up your Next.js application.
Install next-themes
next-themes is:
An abstraction for themes in your Next.js app.
Implementing Dark Mode
Implementing dark mode in Next.js is effortlessly achieved through the dark variant in Tailwind CSS. Simply prefix properties with dark: to designate them for dark mode. For instance, utilizing dark:text-red-700 adjusts the text color to red-700 when the theme is switched to dark.
By default, Next.js aligns with system preferences for theme selection. Nevertheless, to seamlessly toggle between light and dark modes, configure the darkMode strategy to 'class' in the tailwind.config.js file:
darkMode: "class",
Setup your ThemeProvider
next-themes
needs a ThemeProvider to manage themes in your project. You can either create a special component or wrap your main layout with the ThemeProvider
component from next-themes to make it work.
Custom Component (Import this into your layout.tsx
file):
"use client";
import * as React from "react";
import { ThemeProvider } from "next-themes";
type Props = {
children?: React.ReactNode;
};
export function ThemeProvider({children}) {
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
);
}
Using the Existing Component in your layout.tsx
file:
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "My NextJS Web App",
description: "Setting up Dark Mode in NextJS!",
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
</body>
</html>
);
}
Set up some Global Styles:
Next, let's set up some global styles for things like background color and text appearance when switching modes. We'll handle this in our globals.css file.
@layer base {
body {
@apply dark:bg-[#0a0a0a]
bg-[#edf6f9];
}
}
Ensuring your application is accessible in both light and dark modes is crucial. When selecting text and background colors, prioritize adequate contrast. You can evaluate your application's accessibility with tools such as the Accessibility Insights browser extension.
Add your ThemeToggle Component:
Now, we require a component for seamless theme switching. Utilizing the useTheme
hook enables us to determine the current theme, and incorporating an onClick
event facilitates state transitions. Initially, we establish our theme to align with the system theme.
"use client";
import React from "react";
import { useTheme } from "next-themes";
import { RiMoonLine, RiSunLine } from "react-icons/ri";
const DarkModeToggle = () => {
const { theme, setTheme } = useTheme();
return (
<button
onClick={() => (theme == "dark" ? setTheme("light") : setTheme("dark"))}>
{theme === "light" ? (
<RiMoonLine/>
) : (
<RiSunLine/>
)}
</button>
);
};
export default DarkModeToggle;
What's next
Import the ThemeToggle
Component into your application, and you're all set! It's essential to note that to fully experience the capabilities of next-themes
, you'll need to incorporate styles for dark mode by using the dark:
prefix throughout your entire app. That concludes the setup!
Top comments (2)
Thanks, what a clean approach!
thanks!