useDark()
Last updated: 24/04/2026
Overview
useDark combines usePreferredDark (system preference) with useLocalStorage so the user’s manual choice survives reloads: the boolean stored under storageKey seeds from the OS when no value exists, then an effect toggles classNameDark / classNameLight on element (default <html>) whenever isDark changes-handy for Tailwind-style class="dark" roots or scoped theme containers. The tuple [isDark, set, reset] mirrors common ergonomics: set(next) persists the override, reset() removes the key so the next read falls back to usePreferredDark again. Pass a custom element when you only want to theme a subtree (portal, embed) instead of the whole document.
What it accepts
- Optional
storageKey-localStoragekey for the boolean. Default'use-react-color-scheme'. - Optional
classNameDark/classNameLight- Classes toggled exclusively onelement. Defaults'dark'/'light'. - Optional
element- Node receiving classes; defaultdocument.documentElementin the browser,nullduring SSR.
What it returns
- Tuple
[isDark, set, reset]- Current dark flag, setter, and storage reset.
Usage
Explicit options: custom key, class names, and document.documentElement so the snippet shows every parameter (same behavior as defaults, but visible).
import useDark from '@dedalik/use-react/useDark'
function Example() {
const [isDark, setDark, resetDark] = useDark({
storageKey: 'docs:use-dark-demo',
classNameDark: 'demo-dark',
classNameLight: 'demo-light',
element: typeof document !== 'undefined' ? document.documentElement : null,
})
return (
<div>
<h3>Theme</h3>
<p>
Stored dark mode: <strong>{isDark ? 'on' : 'off'}</strong> (see <code><html></code> class list in
devtools).
</p>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<button type='button' onClick={() => setDark(true)}>
Dark
</button>
<button type='button' onClick={() => setDark(false)}>
Light
</button>
<button type='button' onClick={resetDark}>
Reset (follow system)
</button>
</div>
</div>
)
}
export default function Demo() {
return <Example />
}API Reference
useDark
Signature: useDark(options?: UseDarkOptions): [boolean, (next: boolean) => void, () => void]
Parameters
Optional UseDarkOptions:
storageKey(string) - Key for persisted boolean. Default'use-react-color-scheme'.classNameDark/classNameLight(string) - Mutually exclusive classes onelement. Defaults'dark'/'light'.element(HTMLElement | null) - Target forclassList.toggle. Defaultdocument.documentElementwhendocumentexists.
Returns
Tuple:
isDark(boolean) - Persisted value (initialized from system preference when unset).set((next: boolean) => void) - Updates storage and triggers class sync.reset(() => void) - Removes the storage entry so preference reverts to system on next read.
Copy-paste hook
TypeScript
import { useCallback, useEffect } from 'react'
import useLocalStorage from './useLocalStorage'
import usePreferredDark from './usePreferredDark'
export interface UseDarkOptions {
storageKey?: string
classNameDark?: string
classNameLight?: string
element?: HTMLElement | null
}
/**
* Manages dark mode preference and syncs DOM classes.
*/
export default function useDark(options: UseDarkOptions = {}): [boolean, (next: boolean) => void, () => void] {
const {
storageKey = 'use-react-color-scheme',
classNameDark = 'dark',
classNameLight = 'light',
element = typeof document !== 'undefined' ? document.documentElement : null,
} = options
const preferredDark = usePreferredDark()
const [isDark, setIsDark, removeIsDark] = useLocalStorage<boolean>(storageKey, preferredDark)
useEffect(() => {
if (!element) return
element.classList.toggle(classNameDark, isDark)
element.classList.toggle(classNameLight, !isDark)
}, [classNameDark, classNameLight, element, isDark])
const set = useCallback((next: boolean) => setIsDark(next), [setIsDark])
const reset = useCallback(() => removeIsDark(), [removeIsDark])
return [isDark, set, reset]
}JavaScript
import { useCallback, useEffect } from 'react'
import useLocalStorage from './useLocalStorage'
import usePreferredDark from './usePreferredDark'
export default function useDark(options = {}) {
const {
storageKey = 'use-react-color-scheme',
classNameDark = 'dark',
classNameLight = 'light',
element = typeof document !== 'undefined' ? document.documentElement : null,
} = options
const preferredDark = usePreferredDark()
const [isDark, setIsDark, removeIsDark] = useLocalStorage(storageKey, preferredDark)
useEffect(() => {
if (!element) return
element.classList.toggle(classNameDark, isDark)
element.classList.toggle(classNameLight, !isDark)
}, [classNameDark, classNameLight, element, isDark])
const set = useCallback((next) => setIsDark(next), [setIsDark])
const reset = useCallback(() => removeIsDark(), [removeIsDark])
return [isDark, set, reset]
}