A theme provider that applies a light or dark class to the document root, plus a button that switches between the two. Use it to add a persistent light/dark mode switch to a layout header.
Install
pnpm dlx shadcn@latest add https://sitex.full.dev/r/theme-toggle.jsonUsage
import { ThemeProvider, ThemeToggle } from "@/components/ui/theme-toggle"
export function HeaderThemeToggle() {
return (
<ThemeProvider defaultTheme="system" storageKey="theme">
<ThemeToggle />
</ThemeProvider>
)
}Key parts:
ThemeProviderholds the current theme in React state, writes it tolocalStorageunderstorageKey(default"theme"), and toggles thelight/darkclass ondocument.documentElement.defaultThemeaccepts"light","dark", or"system"(default), wheresystemfollowsprefers-color-scheme.ThemeTogglerenders an icon button (sun/moon) that flips betweenlightanddarkon click. It accepts allbuttonprops and setsaria-pressedanddata-statebased on the active theme.useThemereturns{ theme, setTheme }from the provider context for building custom controls.- The
Themetype ("dark" | "light" | "system") is exported for typing your own code.
Theme state lives entirely on the client, so hydrate the whole tree as an island with a Sitex client directive where you use it in a layout, e.g. <HeaderThemeToggle client:load />. The ThemeToggle must render inside the same island as its ThemeProvider, since the context does not cross island boundaries.