Follow the steps below add dark mode to your Next.js application using Tailwind CSS
Install Tailwind
If you don't have Tailwind already installed, run the following command to install it and its dependencies.
1npm install -D tailwindcss postcss autoprefixer
1npm install -D tailwindcss postcss autoprefixer
1npm install -D tailwindcss postcss autoprefixer
1npm install -D tailwindcss postcss autoprefixer
Run the init command to generate both tailwind.config.js and postcss.config.js.
1npx tailwindcss init -p
1npx tailwindcss init -p
1npx tailwindcss init -p
1npx tailwindcss init -p
Add the paths to all of your template files in your tailwind.config.js file.
1/** @type {import('tailwindcss').Config} */
2module.exports = {
3 content: [
4 "./app/**/*.{js,ts,jsx,tsx,mdx}",
5 "./pages/**/*.{js,ts,jsx,tsx,mdx}",
6 "./components/**/*.{js,ts,jsx,tsx,mdx}",
7
8 // Or if using `src` directory:
9 "./src/**/*.{js,ts,jsx,tsx,mdx}",
10 ],
11 theme: {
12 extend: {},
13 },
14 plugins: [],
15}
1/** @type {import('tailwindcss').Config} */
2module.exports = {
3 content: [
4 "./app/**/*.{js,ts,jsx,tsx,mdx}",
5 "./pages/**/*.{js,ts,jsx,tsx,mdx}",
6 "./components/**/*.{js,ts,jsx,tsx,mdx}",
7
8 // Or if using `src` directory:
9 "./src/**/*.{js,ts,jsx,tsx,mdx}",
10 ],
11 theme: {
12 extend: {},
13 },
14 plugins: [],
15}
1/** @type {import('tailwindcss').Config} */
2module.exports = {
3 content: [
4 "./app/**/*.{js,ts,jsx,tsx,mdx}",
5 "./pages/**/*.{js,ts,jsx,tsx,mdx}",
6 "./components/**/*.{js,ts,jsx,tsx,mdx}",
7
8 // Or if using `src` directory:
9 "./src/**/*.{js,ts,jsx,tsx,mdx}",
10 ],
11 theme: {
12 extend: {},
13 },
14 plugins: [],
15}
1/** @type {import('tailwindcss').Config} */
2module.exports = {
3 content: [
4 "./app/**/*.{js,ts,jsx,tsx,mdx}",
5 "./pages/**/*.{js,ts,jsx,tsx,mdx}",
6 "./components/**/*.{js,ts,jsx,tsx,mdx}",
7
8 // Or if using `src` directory:
9 "./src/**/*.{js,ts,jsx,tsx,mdx}",
10 ],
11 theme: {
12 extend: {},
13 },
14 plugins: [],
15}
Add the @tailwind
directives at the top of your globals.css file.
1@tailwind base;
2@tailwind components;
3@tailwind utilities;
1@tailwind base;
2@tailwind components;
3@tailwind utilities;
1@tailwind base;
2@tailwind components;
3@tailwind utilities;
1@tailwind base;
2@tailwind components;
3@tailwind utilities;
Initial setup
setup the darkMode strategy to class in the tailwind.config.js file
1module.exports = {
2 darkMode: 'class',
3 // ...
4}
1module.exports = {
2 darkMode: 'class',
3 // ...
4}
1module.exports = {
2 darkMode: 'class',
3 // ...
4}
1module.exports = {
2 darkMode: 'class',
3 // ...
4}
Install next-themes
1npm i next-themes
1npm i next-themes
1npm i next-themes
1npm i next-themes
Create a theme provider
1"use client"
2
3import { ThemeProvider as NextThemesProvider } from "next-themes"
4import { type ThemeProviderProps } from "next-themes/dist/types"
5import * as React from "react"
6
7export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
8 return <NextThemesProvider {...props}>{children}</NextThemesProvider>
9}
1"use client"
2
3import { ThemeProvider as NextThemesProvider } from "next-themes"
4import { type ThemeProviderProps } from "next-themes/dist/types"
5import * as React from "react"
6
7export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
8 return <NextThemesProvider {...props}>{children}</NextThemesProvider>
9}
1"use client"
2
3import { ThemeProvider as NextThemesProvider } from "next-themes"
4import { type ThemeProviderProps } from "next-themes/dist/types"
5import * as React from "react"
6
7export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
8 return <NextThemesProvider {...props}>{children}</NextThemesProvider>
9}
1"use client"
2
3import { ThemeProvider as NextThemesProvider } from "next-themes"
4import { type ThemeProviderProps } from "next-themes/dist/types"
5import * as React from "react"
6
7export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
8 return <NextThemesProvider {...props}>{children}</NextThemesProvider>
9}
Wrap your root layout
1import { ThemeProvider } from "@/components/theme-provider"
2
3export default function RootLayout({ children }: RootLayoutProps) {
4 return (
5 <html lang="en" suppressHydrationWarning>
6 <head />
7 <body>
8 <ThemeProvider
9 attribute="class"
10 defaultTheme="system"
11 enableSystem
12 disableTransitionOnChange
13 >
14 {children}
15 </ThemeProvider>
16 </body>
17 </html>
18 )
19}
1import { ThemeProvider } from "@/components/theme-provider"
2
3export default function RootLayout({ children }: RootLayoutProps) {
4 return (
5 <html lang="en" suppressHydrationWarning>
6 <head />
7 <body>
8 <ThemeProvider
9 attribute="class"
10 defaultTheme="system"
11 enableSystem
12 disableTransitionOnChange
13 >
14 {children}
15 </ThemeProvider>
16 </body>
17 </html>
18 )
19}
1import { ThemeProvider } from "@/components/theme-provider"
2
3export default function RootLayout({ children }: RootLayoutProps) {
4 return (
5 <html lang="en" suppressHydrationWarning>
6 <head />
7 <body>
8 <ThemeProvider
9 attribute="class"
10 defaultTheme="system"
11 enableSystem
12 disableTransitionOnChange
13 >
14 {children}
15 </ThemeProvider>
16 </body>
17 </html>
18 )
19}
1import { ThemeProvider } from "@/components/theme-provider"
2
3export default function RootLayout({ children }: RootLayoutProps) {
4 return (
5 <html lang="en" suppressHydrationWarning>
6 <head />
7 <body>
8 <ThemeProvider
9 attribute="class"
10 defaultTheme="system"
11 enableSystem
12 disableTransitionOnChange
13 >
14 {children}
15 </ThemeProvider>
16 </body>
17 </html>
18 )
19}
add the following to your global.css
1@layer base {
2 :root {
3 --background: 0 0% 100%;
4 --foreground: 0 0% 3.9%;
5
6 --card: 0 0% 100%;
7 --card-foreground: 0 0% 3.9%;
8
9 --popover: 0 0% 100%;
10 --popover-foreground: 0 0% 3.9%;
11
12 --primary: 0 0% 9%;
13 --primary-foreground: 0 0% 98%;
14
15 --secondary: 0 0% 96.1%;
16 --secondary-foreground: 0 0% 9%;
17
18 --muted: 0 0% 96.1%;
19 --muted-foreground: 0 0% 45.1%;
20
21 --accent: 0 0% 96.1%;
22 --accent-foreground: 0 0% 9%;
23
24 --destructive: 0 84.2% 60.2%;
25 --destructive-foreground: 0 0% 98%;
26
27 --border: 0 0% 89.8%;
28 --input: 0 0% 89.8%;
29 --ring: 0 0% 3.9%;
30
31 --radius: 0.5rem;
32 }
33
34 .dark {
35 --background: 0 0% 0%;
36 --foreground: 0 0% 98%;
37
38 --card: 0 0% 3.9%;
39 --card-foreground: 0 0% 98%;
40
41 --popover: 0 0% 3.9%;
42 --popover-foreground: 0 0% 98%;
43
44 --primary: 0 0% 98%;
45 --primary-foreground: 0 0% 9%;
46
47 --secondary: 0 0% 14.9%;
48 --secondary-foreground: 0 0% 98%;
49
50 --muted: 0 0% 14.9%;
51 --muted-foreground: 0 0% 63.9%;
52
53 --accent: 0 0% 14.9%;
54 --accent-foreground: 0 0% 98%;
55
56 --destructive: 0 62.8% 30.6%;
57 --destructive-foreground: 0 0% 98%;
58
59 --border: 0 0% 14.9%;
60 --input: 0 0% 14.9%;
61 --ring: 0 0% 83.1%;
62 }
63}
64
65@layer base {
66 body {
67 @apply bg-background text-foreground;
68 }
69}
1@layer base {
2 :root {
3 --background: 0 0% 100%;
4 --foreground: 0 0% 3.9%;
5
6 --card: 0 0% 100%;
7 --card-foreground: 0 0% 3.9%;
8
9 --popover: 0 0% 100%;
10 --popover-foreground: 0 0% 3.9%;
11
12 --primary: 0 0% 9%;
13 --primary-foreground: 0 0% 98%;
14
15 --secondary: 0 0% 96.1%;
16 --secondary-foreground: 0 0% 9%;
17
18 --muted: 0 0% 96.1%;
19 --muted-foreground: 0 0% 45.1%;
20
21 --accent: 0 0% 96.1%;
22 --accent-foreground: 0 0% 9%;
23
24 --destructive: 0 84.2% 60.2%;
25 --destructive-foreground: 0 0% 98%;
26
27 --border: 0 0% 89.8%;
28 --input: 0 0% 89.8%;
29 --ring: 0 0% 3.9%;
30
31 --radius: 0.5rem;
32 }
33
34 .dark {
35 --background: 0 0% 0%;
36 --foreground: 0 0% 98%;
37
38 --card: 0 0% 3.9%;
39 --card-foreground: 0 0% 98%;
40
41 --popover: 0 0% 3.9%;
42 --popover-foreground: 0 0% 98%;
43
44 --primary: 0 0% 98%;
45 --primary-foreground: 0 0% 9%;
46
47 --secondary: 0 0% 14.9%;
48 --secondary-foreground: 0 0% 98%;
49
50 --muted: 0 0% 14.9%;
51 --muted-foreground: 0 0% 63.9%;
52
53 --accent: 0 0% 14.9%;
54 --accent-foreground: 0 0% 98%;
55
56 --destructive: 0 62.8% 30.6%;
57 --destructive-foreground: 0 0% 98%;
58
59 --border: 0 0% 14.9%;
60 --input: 0 0% 14.9%;
61 --ring: 0 0% 83.1%;
62 }
63}
64
65@layer base {
66 body {
67 @apply bg-background text-foreground;
68 }
69}
1@layer base {
2 :root {
3 --background: 0 0% 100%;
4 --foreground: 0 0% 3.9%;
5
6 --card: 0 0% 100%;
7 --card-foreground: 0 0% 3.9%;
8
9 --popover: 0 0% 100%;
10 --popover-foreground: 0 0% 3.9%;
11
12 --primary: 0 0% 9%;
13 --primary-foreground: 0 0% 98%;
14
15 --secondary: 0 0% 96.1%;
16 --secondary-foreground: 0 0% 9%;
17
18 --muted: 0 0% 96.1%;
19 --muted-foreground: 0 0% 45.1%;
20
21 --accent: 0 0% 96.1%;
22 --accent-foreground: 0 0% 9%;
23
24 --destructive: 0 84.2% 60.2%;
25 --destructive-foreground: 0 0% 98%;
26
27 --border: 0 0% 89.8%;
28 --input: 0 0% 89.8%;
29 --ring: 0 0% 3.9%;
30
31 --radius: 0.5rem;
32 }
33
34 .dark {
35 --background: 0 0% 0%;
36 --foreground: 0 0% 98%;
37
38 --card: 0 0% 3.9%;
39 --card-foreground: 0 0% 98%;
40
41 --popover: 0 0% 3.9%;
42 --popover-foreground: 0 0% 98%;
43
44 --primary: 0 0% 98%;
45 --primary-foreground: 0 0% 9%;
46
47 --secondary: 0 0% 14.9%;
48 --secondary-foreground: 0 0% 98%;
49
50 --muted: 0 0% 14.9%;
51 --muted-foreground: 0 0% 63.9%;
52
53 --accent: 0 0% 14.9%;
54 --accent-foreground: 0 0% 98%;
55
56 --destructive: 0 62.8% 30.6%;
57 --destructive-foreground: 0 0% 98%;
58
59 --border: 0 0% 14.9%;
60 --input: 0 0% 14.9%;
61 --ring: 0 0% 83.1%;
62 }
63}
64
65@layer base {
66 body {
67 @apply bg-background text-foreground;
68 }
69}
1@layer base {
2 :root {
3 --background: 0 0% 100%;
4 --foreground: 0 0% 3.9%;
5
6 --card: 0 0% 100%;
7 --card-foreground: 0 0% 3.9%;
8
9 --popover: 0 0% 100%;
10 --popover-foreground: 0 0% 3.9%;
11
12 --primary: 0 0% 9%;
13 --primary-foreground: 0 0% 98%;
14
15 --secondary: 0 0% 96.1%;
16 --secondary-foreground: 0 0% 9%;
17
18 --muted: 0 0% 96.1%;
19 --muted-foreground: 0 0% 45.1%;
20
21 --accent: 0 0% 96.1%;
22 --accent-foreground: 0 0% 9%;
23
24 --destructive: 0 84.2% 60.2%;
25 --destructive-foreground: 0 0% 98%;
26
27 --border: 0 0% 89.8%;
28 --input: 0 0% 89.8%;
29 --ring: 0 0% 3.9%;
30
31 --radius: 0.5rem;
32 }
33
34 .dark {
35 --background: 0 0% 0%;
36 --foreground: 0 0% 98%;
37
38 --card: 0 0% 3.9%;
39 --card-foreground: 0 0% 98%;
40
41 --popover: 0 0% 3.9%;
42 --popover-foreground: 0 0% 98%;
43
44 --primary: 0 0% 98%;
45 --primary-foreground: 0 0% 9%;
46
47 --secondary: 0 0% 14.9%;
48 --secondary-foreground: 0 0% 98%;
49
50 --muted: 0 0% 14.9%;
51 --muted-foreground: 0 0% 63.9%;
52
53 --accent: 0 0% 14.9%;
54 --accent-foreground: 0 0% 98%;
55
56 --destructive: 0 62.8% 30.6%;
57 --destructive-foreground: 0 0% 98%;
58
59 --border: 0 0% 14.9%;
60 --input: 0 0% 14.9%;
61 --ring: 0 0% 83.1%;
62 }
63}
64
65@layer base {
66 body {
67 @apply bg-background text-foreground;
68 }
69}
Adding a toggle button
1"use client"
2import { useTheme } from "next-themes"
3import * as React from "react"
4type IconProps = React.HTMLAttributes<SVGElement>
5
6export function ModeToggle() {
7 const { setTheme, theme } = useTheme()
8
9 return (
10 <button
11 className="inline-flex items-center justify-center whitespace-nowrap px-3 hover:opacity-80"
12 onClick={() => setTheme(theme === "light" ? "dark" : "light")}
13 >
14 <Icons.sun className="dark:-rotate-90 size-5 rotate-0 scale-100 transition-all dark:scale-0" />
15 <Icons.moon className="absolute size-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
16 <span className="sr-only">Toggle theme</span>
17 </button>
18 )
19}
20
21export const Icons = {
22 sun: (props: IconProps) => (
23 <svg
24 xmlns="http://www.w3.org/2000/svg"
25 width="24"
26 height="24"
27 viewBox="0 0 24 24"
28 fill="none"
29 stroke="currentColor"
30 strokeWidth="2"
31 strokeLinecap="round"
32 strokeLinejoin="round"
33 {...props}
34 >
35 <circle cx="12" cy="12" r="4" />
36 <path d="M12 2v2" />
37 <path d="M12 20v2" />
38 <path d="m4.93 4.93 1.41 1.41" />
39 <path d="m17.66 17.66 1.41 1.41" />
40 <path d="M2 12h2" />
41 <path d="M20 12h2" />
42 <path d="m6.34 17.66-1.41 1.41" />
43 <path d="m19.07 4.93-1.41 1.41" />
44 </svg>
45 ),
46 moon: (props: IconProps) => (
47 <svg
48 xmlns="http://www.w3.org/2000/svg"
49 width="24"
50 height="24"
51 viewBox="0 0 24 24"
52 fill="none"
53 stroke="currentColor"
54 strokeWidth="2"
55 strokeLinecap="round"
56 strokeLinejoin="round"
57 {...props}
58 >
59 <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
60 </svg>
61 )
62}
1"use client"
2import { useTheme } from "next-themes"
3import * as React from "react"
4type IconProps = React.HTMLAttributes<SVGElement>
5
6export function ModeToggle() {
7 const { setTheme, theme } = useTheme()
8
9 return (
10 <button
11 className="inline-flex items-center justify-center whitespace-nowrap px-3 hover:opacity-80"
12 onClick={() => setTheme(theme === "light" ? "dark" : "light")}
13 >
14 <Icons.sun className="dark:-rotate-90 size-5 rotate-0 scale-100 transition-all dark:scale-0" />
15 <Icons.moon className="absolute size-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
16 <span className="sr-only">Toggle theme</span>
17 </button>
18 )
19}
20
21export const Icons = {
22 sun: (props: IconProps) => (
23 <svg
24 xmlns="http://www.w3.org/2000/svg"
25 width="24"
26 height="24"
27 viewBox="0 0 24 24"
28 fill="none"
29 stroke="currentColor"
30 strokeWidth="2"
31 strokeLinecap="round"
32 strokeLinejoin="round"
33 {...props}
34 >
35 <circle cx="12" cy="12" r="4" />
36 <path d="M12 2v2" />
37 <path d="M12 20v2" />
38 <path d="m4.93 4.93 1.41 1.41" />
39 <path d="m17.66 17.66 1.41 1.41" />
40 <path d="M2 12h2" />
41 <path d="M20 12h2" />
42 <path d="m6.34 17.66-1.41 1.41" />
43 <path d="m19.07 4.93-1.41 1.41" />
44 </svg>
45 ),
46 moon: (props: IconProps) => (
47 <svg
48 xmlns="http://www.w3.org/2000/svg"
49 width="24"
50 height="24"
51 viewBox="0 0 24 24"
52 fill="none"
53 stroke="currentColor"
54 strokeWidth="2"
55 strokeLinecap="round"
56 strokeLinejoin="round"
57 {...props}
58 >
59 <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
60 </svg>
61 )
62}
1"use client"
2import { useTheme } from "next-themes"
3import * as React from "react"
4type IconProps = React.HTMLAttributes<SVGElement>
5
6export function ModeToggle() {
7 const { setTheme, theme } = useTheme()
8
9 return (
10 <button
11 className="inline-flex items-center justify-center whitespace-nowrap px-3 hover:opacity-80"
12 onClick={() => setTheme(theme === "light" ? "dark" : "light")}
13 >
14 <Icons.sun className="dark:-rotate-90 size-5 rotate-0 scale-100 transition-all dark:scale-0" />
15 <Icons.moon className="absolute size-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
16 <span className="sr-only">Toggle theme</span>
17 </button>
18 )
19}
20
21export const Icons = {
22 sun: (props: IconProps) => (
23 <svg
24 xmlns="http://www.w3.org/2000/svg"
25 width="24"
26 height="24"
27 viewBox="0 0 24 24"
28 fill="none"
29 stroke="currentColor"
30 strokeWidth="2"
31 strokeLinecap="round"
32 strokeLinejoin="round"
33 {...props}
34 >
35 <circle cx="12" cy="12" r="4" />
36 <path d="M12 2v2" />
37 <path d="M12 20v2" />
38 <path d="m4.93 4.93 1.41 1.41" />
39 <path d="m17.66 17.66 1.41 1.41" />
40 <path d="M2 12h2" />
41 <path d="M20 12h2" />
42 <path d="m6.34 17.66-1.41 1.41" />
43 <path d="m19.07 4.93-1.41 1.41" />
44 </svg>
45 ),
46 moon: (props: IconProps) => (
47 <svg
48 xmlns="http://www.w3.org/2000/svg"
49 width="24"
50 height="24"
51 viewBox="0 0 24 24"
52 fill="none"
53 stroke="currentColor"
54 strokeWidth="2"
55 strokeLinecap="round"
56 strokeLinejoin="round"
57 {...props}
58 >
59 <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
60 </svg>
61 )
62}
1"use client"
2import { useTheme } from "next-themes"
3import * as React from "react"
4type IconProps = React.HTMLAttributes<SVGElement>
5
6export function ModeToggle() {
7 const { setTheme, theme } = useTheme()
8
9 return (
10 <button
11 className="inline-flex items-center justify-center whitespace-nowrap px-3 hover:opacity-80"
12 onClick={() => setTheme(theme === "light" ? "dark" : "light")}
13 >
14 <Icons.sun className="dark:-rotate-90 size-5 rotate-0 scale-100 transition-all dark:scale-0" />
15 <Icons.moon className="absolute size-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
16 <span className="sr-only">Toggle theme</span>
17 </button>
18 )
19}
20
21export const Icons = {
22 sun: (props: IconProps) => (
23 <svg
24 xmlns="http://www.w3.org/2000/svg"
25 width="24"
26 height="24"
27 viewBox="0 0 24 24"
28 fill="none"
29 stroke="currentColor"
30 strokeWidth="2"
31 strokeLinecap="round"
32 strokeLinejoin="round"
33 {...props}
34 >
35 <circle cx="12" cy="12" r="4" />
36 <path d="M12 2v2" />
37 <path d="M12 20v2" />
38 <path d="m4.93 4.93 1.41 1.41" />
39 <path d="m17.66 17.66 1.41 1.41" />
40 <path d="M2 12h2" />
41 <path d="M20 12h2" />
42 <path d="m6.34 17.66-1.41 1.41" />
43 <path d="m19.07 4.93-1.41 1.41" />
44 </svg>
45 ),
46 moon: (props: IconProps) => (
47 <svg
48 xmlns="http://www.w3.org/2000/svg"
49 width="24"
50 height="24"
51 viewBox="0 0 24 24"
52 fill="none"
53 stroke="currentColor"
54 strokeWidth="2"
55 strokeLinecap="round"
56 strokeLinejoin="round"
57 {...props}
58 >
59 <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" />
60 </svg>
61 )
62}
Done! Try it out!