How To Implement Light/Dark mode in Next Js
This is a brief tutorial on how to implement dark & light mode in next.Js
special thanks to developerAromal
Prerequisites
- next-themes
- next js project
- lucide-react icons (only if you're using sun/moon toggle icons)
Steps
- Create a new Next Js project using the command
npx create-next-app@latest
- Inside the project folder, install next-theme and lucide-react (it's for creating the Moon/Sun Icon)
npm i next-themes
install lucide-react, if you want to show sun & moon icon
npm i lucide-react
- Create a folder inside app directory named
components
inside components, create two foldersui
andincludes
. Insideui
goes the files :theme-provider.tsx
&theme-switcher.tsx
. Insideincludes
we create aNavbar.tsx
component, ( for putting the light/dark mode toggle )
the folder structure should look like this:
/app
└── /components
├── /ui
│ ├── theme-provider.tsx
│ └── theme-switcher.tsx
└── /includes
└── navbar.tsx
- Inside
theme-provider.tsx
put this code:
"use client";
import * as React from "react";
import { ThemeProvider as NextThemesProvider } from "next-themes";
export function ThemeProvider({
children,
...props
}: React.ComponentProps<typeof NextThemesProvider>) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
}
- Inside
theme-switcher.tsx
put this code:
"use client";
import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes";
export const ThemeSwitcher = () => {
const { setTheme } = useTheme();
return (
<main className="flex gap-6">
<button onClick={() => setTheme("light")}>light</button>
<button onClick={() => setTheme("dark")}>dark</button>
</main>
);
};
you can see that, inside theme-switcher.tsx
comes the toggle functionality, so what you can do is you can put the lucide react icons for sun and moon respectively in the code, to show both icons. Or as you wish ( your creativity !)
- Now call this
theme-switcher.tsx
in youNavbar.tsx
:
"use client";
import { ThemeSwitcher } from "../ui/theme-switcher";
export default function Navbar() {
return (
<header className="bg-white dark:bg-black">
<ThemeSwitcher />
</header>
);
}
I've implemented a simple navbar, you can create a big one as you wish
nb:- the tailwind class on header tag
- Now inside
globals.css
:
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
body {
@apply bg-white text-black dark:bg-black dark:text-white;
}
so what it basically does is the body gets white bg and black text (in light mode) and black bg and white text (in dark mode)
Since tailwind css is also used, you can do the following also :
<div className="bg-white dark:bg-blue-700">
<h1>Hello world </h1>
</div>
- All this won't work until you do the following thing, that is:
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
// add this
import { ThemeProvider } from "./components/ui/theme-provider";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html
lang="en"
className="light"
style={{ colorScheme: "light" }}
suppressHydrationWarning
>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<ThemeProvider
attribute="class"
defaultTheme="light"
enableSystem
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
);
}
you need to wrap the children in the layout.tsx
inside ThemeProvider
and also do the following:
- add
suppressHydrationWarning
to html element - wrap the {children} in
ThemeProvider
with the above attributes
- Now call the
Navbar.tsx
and add some dummy contents topage.tsx
to see if it's working or not:
import Navbar from "./components/includes/Navbar";
export default function Home() {
return (
<section
id="main"
className="min-h-screen p-20 flex flex-col-reverse items-center justify-center"
>
<Navbar />
<h1 className="text-center mb-20">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Facere fugit
quam quae in aut odit veniam quaerat, sapiente similique incidunt quis
consequatur nulla obcaecati dolorum ipsam enim possimus perspiciatis
sit.
</h1>
</section>
);
}
- Try clicking on the light/dark mode to see the changes
Hope it worked !
Extra Help
check out the github repo to try yourself :
next-js-dark-light-mode
give this repo a star ⭐ if this helped you !
Again special thanks to developerAromal for helping
Check out his dev.to account : @developeraromal
Ask your doubts in the comments 😎🫵
Top comments (0)