Let's create a dark mode / theme switch for NextJS App Dir.
## Creating a NextJS app
Open up the terminal in your desired folder, then run any of these commands as per your preferred package manager. (You can skip to the next section if you already have a NextJS 13 app)
npx create-next-app@latest
yarn create next-app
pnpm create next-app
bunx create-next-app
Complete the prompts.
## Installing and setting up themes
Install next-themes:
npm i next-themes
yarn/pnpm/bun add next-themes
# Optional: Installing a icon library
npm i lucide-react
yarn/pnpm/bun add lucide-react
After those have been installed, you can open up the project dir in your favourite code editor. Navigate to /app
and create a providers.tsx
or providers.jsx
file depending on your preferred language.
1// app/providers.tsx
2
3"use client";
4
5import { ThemeProvider } from "next-themes";
6
7const Providers = ({ children }: { children: React.ReactNode }) => {
8 return (
9 <ThemeProvider
10 attribute="class" // Setting the theme using class="" in <html /> tag
11 enableSystem // For automatically setting the theme
12 >
13 {children}
14 </ThemeProvider>
15 );
16};
17
18export default Providers;
You can view more options for the <ThemeProvider />
here: https://github.com/pacocoursey/next-themes#api
Import the providers.tsx/jsx
file into your layout.tsx/jsx
file, then wrap your {children}
in the providers.
1// app/layout.tsx
2
3import "./globals.css";
4
5import Providers from "./providers";
6
7export default function RootLayout({
8 children,
9}: {
10 children: React.ReactNode;
11}) {
12 return (
13 <html lang="en">
14 <body>
15 <Providers>
16 {children}
17 </Providers>
18 </body>
19 </html>
20 );
21}
## Creating the theme switch
Now for the user to be able to switch themes, we can create a toggle or a button or a select. We going to be using a button component for switching themes in this post.
Start by creating a components
folder in your root dir, inside that create a folder called theme-switch
and a index.tsx/jsx
file inside it. The folder layout should look like this:
components/
- theme-switch/
- index.tsx
Open the index.tsx/jsx
file, and let's start with the code.
1"use client";
2
3import { useTheme } from "next-themes";
4import { Moon, Sun, SunMoon } from "lucide-react"; // Optional, you can use other icon libraries too
5
6export const ThemeSwitch = () => {
7 const { theme, setTheme } = useTheme();
8
9 const handleTheme = () => {
10 setTheme(theme === "light" ? "dark" : "light");
11 };
12
13 return (
14 <button
15 shape="icon"
16 className="h-11 w-11 rounded-sm aspect-square p-2.5"
17 onClick={handleTheme}
18 >
19 {theme === "light" ? <Sun /> : theme == "dark" ? <Moon /> : <SunMoon />}
20 </button>
21 );
22};
That'd be it! You can now import this lets say a <NavBar />
component use it!
## Styling
We can style our themes in different ways, I'm going to show by TailwindCSS and normal CSS. Starting with TailwindCSS, open your tailwind.config.ts/js
file then add darkMode: "class", as one of the options in the config. It should look something like this:
1import type { Config } from "tailwindcss";
2
3const config: Config = {
4 darkMode: "class",
5 // Your other options
6};
7export default config;
Then you can define your styles using in your classNames
by prefixing dark:
before the styling for dark mode.
1// Some page or component
2
3export const Component = () => {
4 return <div className="rounded-xl p-4 bg-black text-white dark:bg-white dark:text-black" />;
5}
If you're using CSS variables, then you can use this instead. Open you app/global.css
file then:
1:root {
2 --primary: azure;
3 --secondary: gray;
4}
5
6/* Changing the variables if theme is dark */
7html.dark {
8 --primary: gray;
9 --secondary: azure;
10}
11
12.body {
13 /* Will automatically change once theme is switched */
14 background: var(--secondary);
15 color: var(--primary)
16}
## That's it!
Now you can create your super-cool website with support for both dark/light mode or any colour! Have fun!