Trouble Implementing Dark Mode (Shadcn UI) in Next.js Project Using App Directory
Answered
Miniature Schnauzer posted this in #help-forum
Miniature SchnauzerOP
I'm currently working on adding dark mode functionality to my Next.js project using the new app directory structure, and I've run into a bit of a snag. Despite the toggle button for switching themes registering click events (as shown in my console logs), the theme doesn't seem to change across my components as expected.
Here's a brief overview of how I've set things up:
- Toggle Mode Component: This component is responsible for switching between light and dark themes. It utilizes the
Here's a brief overview of how I've set things up:
- Toggle Mode Component: This component is responsible for switching between light and dark themes. It utilizes the
useTheme hook from next-themes to set the theme accordingly.'use client';
import * as React from "react"
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function ModeToggle() {
const { setTheme } = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => { setTheme("light"); console.log("Theme set to light"); }}>
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => { setTheme("dark"); console.log("Theme set to dark"); }}>
Dark
</DropdownMenuItem>
<DropdownMenuItem onClick={() => { setTheme("system"); console.log("Theme set to system preference"); }}>
System
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}7 Replies
@Miniature Schnauzer I'm currently working on adding dark mode functionality to my Next.js project using the new app directory structure, and I've run into a bit of a snag. Despite the toggle button for switching themes registering click events (as shown in my console logs), the theme doesn't seem to change across my components as expected.
Here's a brief overview of how I've set things up:
- **Toggle Mode Component:** This component is responsible for switching between light and dark themes. It utilizes the `useTheme` hook from `next-themes` to set the theme accordingly.
typescript
'use client';
import * as React from "react"
import { Moon, Sun } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function ModeToggle() {
const { setTheme } = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => { setTheme("light"); console.log("Theme set to light"); }}>
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => { setTheme("dark"); console.log("Theme set to dark"); }}>
Dark
</DropdownMenuItem>
<DropdownMenuItem onClick={() => { setTheme("system"); console.log("Theme set to system preference"); }}>
System
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
Miniature SchnauzerOP
- Layout Component: My layout component wraps around the main application and should respond to theme changes. It's where I use the
ThemeProvider from next-themes.import "./globals.css";
import { getSessionStatus } from "./actions/AuthActions/isUserLoggedIn";
import ClientLayout from "./components/ClientLayout";
import { Inter as FontSans } from "next/font/google";
import { cn } from "@/lib/utils";
import { ThemeProvider } from "../components/theme-provider";
const fontSans = FontSans({
subsets: ['latin'],
variable: "--font-sans",
})
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const isLoggedIn = await getSessionStatus();
return (
<html lang="en" suppressHydrationWarning>
<body
className={cn(
"min-h-screen bg-background font-sans antialiased",
fontSans.variable
)}
>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
></ThemeProvider>
<div>
<ClientLayout isLoggedIn={isLoggedIn}></ClientLayout>
{children}
</div>
</body>
</html>
);
}Demonstration Video: This video showcases the issue at hand, where clicking the toggle button logs the theme change in the console but doesn't visually update the UI components as expected.
https://github.com/shadcn-ui/ui/assets/55926702/3b5b8875-6459-4832-8bdf-8837422bbdce
I've double-checked my implementation against the documentation and various tutorials, but I can't seem to pinpoint where the issue lies. Any insights, suggestions, or guidance on what might be going wrong would be greatly appreciated!
Thank you in advance for your help!
https://github.com/shadcn-ui/ui/assets/55926702/3b5b8875-6459-4832-8bdf-8837422bbdce
I've double-checked my implementation against the documentation and various tutorials, but I can't seem to pinpoint where the issue lies. Any insights, suggestions, or guidance on what might be going wrong would be greatly appreciated!
Thank you in advance for your help!
@Miniature Schnauzer **Demonstration Video:** This video showcases the issue at hand, where clicking the toggle button logs the theme change in the console but doesn't visually update the UI components as expected.
https://github.com/shadcn-ui/ui/assets/55926702/3b5b8875-6459-4832-8bdf-8837422bbdce
I've double-checked my implementation against the documentation and various tutorials, but I can't seem to pinpoint where the issue lies. Any insights, suggestions, or guidance on what might be going wrong would be greatly appreciated!
Thank you in advance for your help!
Miniature SchnauzerOP
I've made some progress in debugging the dark mode functionality in my Next.js project. To further investigate, I added console logs to capture the current theme state recognized by
However, regardless of the theme change actions, the
This suggests that there might be an issue with how the theme context is being provided or consumed within my application. Perhaps this additional information could shed some light on what might be causing the issue. Any further assistance or insights would be greatly appreciated. :)
next-themes:const { theme, setTheme } = useTheme(); // Destructure theme from useTheme
<DropdownMenuItem onClick={() => { setTheme("dark"); console.log("Theme set to dark but in reality it is", theme); }}>
<DropdownMenuItem onClick={() => { setTheme("system"); console.log("Theme set to system preference"); }}>However, regardless of the theme change actions, the
theme variable remains undefined, as shown in the console logs:Current theme: undefined
botonDarkMode.tsx:20 Current theme: undefined
botonDarkMode.tsx:33 Theme set to light but in reality it is undefined
botonDarkMode.tsx:36 Theme set to dark but in reality it is undefined
botonDarkMode.tsx:33 Theme set to light but in reality it is undefinedThis suggests that there might be an issue with how the theme context is being provided or consumed within my application. Perhaps this additional information could shed some light on what might be causing the issue. Any further assistance or insights would be greatly appreciated. :)
Answer
like this
Miniature SchnauzerOP
That solved the issue :D. Thank you so much!