Theme Switcher
21st.devA theme switcher component with smooth animations between light, dark, and system modes.
Current: system
import { ThemeSwitcher } from "@/registry/optics/theme-switcher";import { useTheme } from "next-themes";import { useModeAnimation, ThemeAnimationType,} from "react-theme-switch-animation";import * as React from "react";export function MyComponent() { const [themeSwitch, setThemeSwitch] = React.useState("system"); const { theme, setTheme, resolvedTheme, systemTheme } = useTheme(); const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation(); const checkTheme = () => { let tema = resolvedTheme; if (tema === "system") { tema = systemTheme; } return tema === "light" ? false : true; }; const handleSetTheme = (newTheme) => { let temaActual = localStorage.getItem("theme2"); setThemeSwitch(newTheme); if (newTheme === "system") { if (systemTheme === localStorage.getItem("theme")) return setTimeout(() => { localStorage.setItem("theme2", newTheme); }, 200); toggleSwitchTheme({ animationType: ThemeAnimationType.BLUR_CIRCLE, isDarkMode: checkTheme(), onDarkModeChange: null, }); return setTimeout(() => { localStorage.setItem("theme2", newTheme); }, 200); } if ( newTheme === localStorage.getItem("theme") || (temaActual === "system" && systemTheme === newTheme && temaActual !== newTheme) ) return setTimeout(() => { localStorage.setItem("theme2", newTheme); }, 200); toggleSwitchTheme({ animationType: ThemeAnimationType.BLUR_CIRCLE, isDarkMode: checkTheme(), onDarkModeChange: null, }); setTimeout(() => { localStorage.setItem("theme2", newTheme); }, 200); }; React.useEffect(() => { let tema = localStorage.getItem("theme2") || "system"; setThemeSwitch(tema); localStorage.setItem("theme", tema === "system" ? resolvedTheme : tema); }, [resolvedTheme]); React.useEffect(() => { if ( systemTheme !== localStorage.getItem("theme") && localStorage.getItem("theme2") === "system" ) { toggleSwitchTheme({ animationType: ThemeAnimationType.BLUR_CIRCLE, isDarkMode: localStorage.getItem("theme") === "light" ? false : true, onDarkModeChange: null, }); } }, [systemTheme, toggleSwitchTheme]); return ( <ThemeSwitcher ref={ref} defaultValue={themeSwitch} onChange={handleSetTheme} value={themeSwitch} /> );}import { ThemeSwitcher } from "@/registry/optics/theme-switcher";import { useTheme } from "next-themes";import { useModeAnimation, ThemeAnimationType,} from "react-theme-switch-animation";import * as React from "react";export function MyComponent() { const [themeSwitch, setThemeSwitch] = React.useState("system"); const { theme, setTheme, resolvedTheme, systemTheme } = useTheme(); const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation(); const checkTheme = () => { let tema = resolvedTheme; if (tema === "system") { tema = systemTheme; } return tema === "light" ? false : true; }; const handleSetTheme = (newTheme) => { let temaActual = localStorage.getItem("theme2"); setThemeSwitch(newTheme); if (newTheme === "system") { if (systemTheme === localStorage.getItem("theme")) return setTimeout(() => { localStorage.setItem("theme2", newTheme); }, 200); toggleSwitchTheme({ animationType: ThemeAnimationType.BLUR_CIRCLE, isDarkMode: checkTheme(), onDarkModeChange: null, }); return setTimeout(() => { localStorage.setItem("theme2", newTheme); }, 200); } if ( newTheme === localStorage.getItem("theme") || (temaActual === "system" && systemTheme === newTheme && temaActual !== newTheme) ) return setTimeout(() => { localStorage.setItem("theme2", newTheme); }, 200); toggleSwitchTheme({ animationType: ThemeAnimationType.BLUR_CIRCLE, isDarkMode: checkTheme(), onDarkModeChange: null, }); setTimeout(() => { localStorage.setItem("theme2", newTheme); }, 200); }; React.useEffect(() => { let tema = localStorage.getItem("theme2") || "system"; setThemeSwitch(tema); localStorage.setItem("theme", tema === "system" ? resolvedTheme : tema); }, [resolvedTheme]); React.useEffect(() => { if ( systemTheme !== localStorage.getItem("theme") && localStorage.getItem("theme2") === "system" ) { toggleSwitchTheme({ animationType: ThemeAnimationType.BLUR_CIRCLE, isDarkMode: localStorage.getItem("theme") === "light" ? false : true, onDarkModeChange: null, }); } }, [systemTheme, toggleSwitchTheme]); return ( <ThemeSwitcher ref={ref} defaultValue={themeSwitch} onChange={handleSetTheme} value={themeSwitch} /> );}Installation
pnpm dlx shadcn@latest add https://optics.agusmayol.com.ar/r/theme-switcher.json
Props
<ThemeSwitcher />
Name
Type
className
string
value
"system" | "light" | "dark"
onChange
(theme: string) => void
defaultValue
"system" | "light" | "dark" (default: "system")