# useTernaryDarkMode > Three-state dark mode — system, dark or light — persisted. - Category: State - Package: `hookli` (install with `npm i hookli`) - Docs: https://hookli.vercel.app/docs/use-ternary-dark-mode ## Signature ```ts useTernaryDarkMode(options?: UseTernaryDarkModeOptions): UseTernaryDarkModeReturn ``` ## Parameters - `options`: `UseTernaryDarkModeOptions` (default: `{}`) — Optional starting mode and localStorage key. ## Returns - `{ … }`: `UseTernaryDarkModeReturn` — The resolved isDarkMode boolean, the stored ternary preference, and its setters. ## Types ### TernaryDarkMode The three possible preferences. - `value`: `"system" | "dark" | "light"` — "system" resolves against the OS; "dark"/"light" force a mode. ### UseTernaryDarkModeOptions Optional starting mode and persistence key. - `defaultValue`: `TernaryDarkMode` (default: `"system"`) — The mode before anything is stored: "system", "dark" or "light". - `localStorageKey`: `string` (default: `"hookli-ternary-dark-mode"`) — The localStorage key the choice is persisted under. ### UseTernaryDarkModeReturn The resolved mode plus setters. - `isDarkMode`: `boolean` — True when the mode is "dark", or "system" while the OS prefers dark. - `ternaryDarkMode`: `TernaryDarkMode` — The stored preference: "system" | "dark" | "light". - `setTernaryDarkMode`: `(value: TernaryDarkMode | ((prev: TernaryDarkMode) => TernaryDarkMode)) => void` — Set the preference directly; accepts a value or an updater. - `toggleTernaryDarkMode`: `() => void` — Cycle the preference: light → system → dark → light. ## Usage ```tsx import { useTernaryDarkMode } from "hookli"; export function Demo() { const { isDarkMode, ternaryDarkMode, setTernaryDarkMode } = useTernaryDarkMode(); return (
); } ``` ## Source `src/hooks/use-ternary-dark-mode/use-ternary-dark-mode.ts` ```ts import { useCallback } from "react"; import { useLocalStorage } from "../use-local-storage/use-local-storage"; import { useMediaQuery } from "../use-media-query/use-media-query"; type TernaryDarkMode = "system" | "dark" | "light"; interface UseTernaryDarkModeOptions { defaultValue?: TernaryDarkMode; localStorageKey?: string; } interface UseTernaryDarkModeReturn { isDarkMode: boolean; ternaryDarkMode: TernaryDarkMode; setTernaryDarkMode: ( value: TernaryDarkMode | ((prev: TernaryDarkMode) => TernaryDarkMode), ) => void; toggleTernaryDarkMode: () => void; } const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)"; const DEFAULT_STORAGE_KEY = "hookli-ternary-dark-mode"; export function useTernaryDarkMode( options: UseTernaryDarkModeOptions = {}, ): UseTernaryDarkModeReturn { const { defaultValue = "system", localStorageKey = DEFAULT_STORAGE_KEY } = options; const isDarkOS = useMediaQuery(COLOR_SCHEME_QUERY); const { value: ternaryDarkMode, setStoredValue: setTernaryDarkMode } = useLocalStorage(localStorageKey, defaultValue); const isDarkMode = ternaryDarkMode === "dark" || (ternaryDarkMode === "system" && isDarkOS); const toggleTernaryDarkMode = useCallback(() => { const cycle: TernaryDarkMode[] = ["light", "system", "dark"]; setTernaryDarkMode((prev) => { const nextIndex = (cycle.indexOf(prev) + 1) % cycle.length; return cycle[nextIndex]; }); }, [setTernaryDarkMode]); return { isDarkMode, ternaryDarkMode, setTernaryDarkMode, toggleTernaryDarkMode, }; } ```