Theme Switcher
lyminhnghia/theme-switcherFreeComponent
Toggle between system, light, and dark themes in Next.js apps.
Install it
npx shadcn@latest add https://lyminhnghia.github.io/r/theme-switcher.jsonSource
1"use client"23import { MonitorIcon, MoonStarIcon, SunIcon } from "lucide-react"4import { motion } from "motion/react"5import { useTheme } from "next-themes"6import type { JSX } from "react"7import { useSyncExternalStore } from "react"89import { cn } from "@/lib/utils"1011function ThemeOption({12 icon,13 value,14 isActive,15 onClick,16}: {17 icon: JSX.Element18 value: string19 isActive?: boolean20 onClick: (value: string) => void21}) {22 return (23 <button24 className={cn(25 "relative flex size-8 cursor-default items-center justify-center rounded-full transition-[color] [&_svg]:size-4",26 isActive27 ? "text-zinc-950 dark:text-zinc-50"28 : "text-zinc-400 hover:text-zinc-950 dark:text-zinc-500 dark:hover:text-zinc-50"29 )}30 role="radio"31 aria-checked={isActive}32 aria-label={`Switch to ${value} theme`}33 onClick={() => onClick(value)}34 >35 {icon}3637 {isActive && (38 <motion.div39 layoutId="theme-option"40 transition={{ type: "spring", bounce: 0.3, duration: 0.6 }}41 className="absolute inset-0 rounded-full border border-zinc-200 dark:border-zinc-700"42 />43 )}44 </button>45 )46}4748const THEME_OPTIONS = [49 {50 icon: <MonitorIcon />,51 value: "system",52 },53 {54 icon: <SunIcon />,55 value: "light",56 },57 {58 icon: <MoonStarIcon />,59 value: "dark",60 },61]6263function ThemeSwitcher() {64 const { theme, setTheme } = useTheme()6566 const isMounted = useSyncExternalStore(67 () => () => {},68 () => true,69 () => false70 )7172 if (!isMounted) {73 return <div className="flex h-8 w-24" />74 }7576 return (77 <motion.div78 key={String(isMounted)}79 initial={{ opacity: 0 }}80 animate={{ opacity: 1 }}81 transition={{ duration: 0.3 }}82 className="inline-flex items-center overflow-hidden rounded-full bg-white ring-1 ring-zinc-200 ring-inset dark:bg-zinc-950 dark:ring-zinc-700"83 role="radiogroup"84 >85 {THEME_OPTIONS.map((option) => (86 <ThemeOption87 key={option.value}88 icon={option.icon}89 value={option.value}90 isActive={theme === option.value}91 onClick={setTheme}92 />93 ))}94 </motion.div>95 )96}9798export { ThemeSwitcher }
What it pulls in
npm packages
Files it writes
More from lyminhnghia
All 26 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Apple Hello Effectapple-hello-effect | lyminhnghia | Components | Free | 1 dep | |
| chevrons-up-down-iconchevrons-up-down-icon | lyminhnghia | Components | Free | no deps | |
| Code Block Commandcode-block-command | lyminhnghia | Components | Free | 4 deps · 3 files | |
| Consent Managerconsent-manager | lyminhnghia | Components | Free | 1 dep | |
| Copy Buttoncopy-button | lyminhnghia | Components | Free | 2 deps · 2 files | |
| GitHub Starsgithub-stars | lyminhnghia | Components | Free | no deps | |
| Scroll Fade Effectscroll-fade-effect | lyminhnghia | Components | Free | no deps | |
| Shimmering Textshimmering-text | lyminhnghia | Components | Free | 1 dep |
