Foundationcomponent
Theme toggle
Light, dark, and system theme switcher.
Light, dark, or follow the system. Persists across reloads.
Installation
npx shadcn@latest add @particular/theme-togglenpm dependencies
- lucide-react@^1.51.0
- next-themes@^0.4.6
Installs these registry items
Source
"use client"
import * as React from "react"
import { MonitorIcon, MoonIcon, SunIcon } from "lucide-react"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
const options = [
{ value: "light", label: "Light", icon: SunIcon },
{ value: "dark", label: "Dark", icon: MoonIcon },
{ value: "system", label: "System", icon: MonitorIcon },
] as const
function ThemeToggle({
variant = "ghost",
size = "icon-sm",
className,
}: Pick<React.ComponentProps<typeof Button>, "variant" | "size" | "className">) {
const { theme, setTheme } = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger
render={<Button variant={variant} size={size} className={className} aria-label="Change theme" />}
>
<SunIcon className="dark:hidden" />
<MoonIcon className="hidden dark:block" />
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-36">
<DropdownMenuRadioGroup value={theme ?? "system"} onValueChange={(value) => setTheme(String(value))}>
{options.map(({ value, label, icon: Icon }) => (
<DropdownMenuRadioItem key={value} value={value}>
<Icon />
{label}
</DropdownMenuRadioItem>
))}
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
)
}
export { ThemeToggle }