--- title: Theme preference description: Build a complete light, dark, and system theme preference flow. order: 30 toc: - id: define-theme-mode title: Define theme mode - id: apply-the-theme title: Apply the theme - id: render-a-control title: Render a control --- ## Define theme mode {#define-theme-mode} ```ts import "@workspace/preferences" declare module "@workspace/preferences" { interface PreferencesCustom { "theme-mode": "light" | "dark" | "system" } } ``` Load the cookie on the server and pass the parsed value through `initialPreferences` so server markup and hydration share the same snapshot. ## Apply the theme {#apply-the-theme} ```tsx const themeEffects = [ { layoutEffect: ({ preferences }) => { const systemDark = window.matchMedia( "(prefers-color-scheme: dark)" ).matches const dark = preferences["theme-mode"] === "dark" || (preferences["theme-mode"] === "system" && systemDark) document.documentElement.classList.toggle("dark", dark) document.documentElement.style.colorScheme = dark ? "dark" : "light" }, }, ] satisfies readonly PreferenceEffect[] ``` ## Render a control {#render-a-control} ```tsx function ThemeModeSelect() { const [themeMode, setThemeMode] = usePreference("theme-mode") return ( ) } ```