Overview
Six theme switcher variants for toggling between light and dark modes. Built with next-themes
for hydration-safe rendering and smooth animations.
Components
Theme Switcher
Classic switch with fading sun/moon icons.
Theme Switcher Switch
Centered switch variant with smaller icons.
Theme Switcher Button
Icon button with rotating animation
Theme Switcher Dropdown
Menu with Light, Dark, and System options.
Theme Switcher Toggle
Custom toggle with sliding icon.
Theme Switcher Multi Button
Segmented control showing all options at once.
Installation
Install any variant:
bunx shadcn@latest add @elements/theme-switcher
Install all variants:
bunx shadcn@latest add @elements/theme-switcher @elements/theme-switcher-switch @elements/theme-switcher-button @elements/theme-switcher-dropdown @elements/theme-switcher-toggle @elements/theme-switcher-multi-button
Setup
1. Install next-themes
npm install next-themes
2. Configure ThemeProvider
import { ThemeProvider } from "next-themes";
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
</body>
</html>
);
}
3. Configure Tailwind
module.exports = {
darkMode: ["class"],
}
Usage
import { ThemeSwitcher } from "@/components/elements/theme-switcher";
export default function Header() {
return (
<header>
<ThemeSwitcher />
</header>
);
}
Which Variant to Use?
Variant | System Support | Best For |
---|---|---|
Switcher | No | Headers, navbars |
Switch | No | Compact spaces |
Button | No | Toolbars |
Dropdown | Yes | Settings pages |
Toggle | No | Mobile UIs |
Multi Button | Yes | Dashboards |
Note: Only Dropdown and Multi Button support system theme preference.
Advanced
Programmatic Control
"use client";
import { useTheme } from "next-themes";
export function ThemeControl() {
const { theme, setTheme } = useTheme();
return (
<button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
Toggle Theme
</button>
);
}
Responsive Usage
import { ThemeSwitcherButton } from "@/components/elements/theme-switcher-button";
import { ThemeSwitcherDropdown } from "@/components/elements/theme-switcher-dropdown";
export default function Nav() {
return (
<>
<div className="md:hidden">
<ThemeSwitcherButton />
</div>
<div className="hidden md:block">
<ThemeSwitcherDropdown />
</div>
</>
);
}
Troubleshooting
Theme not changing? Verify ThemeProvider
wraps your app and attribute="class"
is set.
Hydration warnings? Add suppressHydrationWarning
to <html>
tag.
System theme not working? Use Dropdown or Multi Button variants (others don't support system preference).