useDarkMode()

This React Hook offers you an interface to enable, disable, toggle and read the dark theme mode. The returned value (isDarkMode) is a boolean to let you be able to use with your logic.

It uses internally useLocalStorage() to persist the value and listens the OS color scheme preferences.

The Hook

1import { useEffect } from 'react'
2
3import { useLocalStorage } from '../useLocalStorage'
4
5const COLOR_SCHEME_QUERY = '(prefers-color-scheme: dark)'
6
7interface UseDarkModeOutput {
8 isDarkMode: boolean
9 toggle: () => void
10 enable: () => void
11 disable: () => void
12}
13
14function useDarkMode(defaultValue?: boolean): UseDarkModeOutput {
15 const getPrefersScheme = (): boolean => {
16 // Prevents SSR issues
17 if (typeof window !== 'undefined') {
18 return window.matchMedia(COLOR_SCHEME_QUERY).matches
19 }
20
21 return !!defaultValue
22 }
23
24 const [isDarkMode, setDarkMode] = useLocalStorage<boolean>(
25 'darkMode',
26 getPrefersScheme(),
27 )
28
29 // Update darkMode if os prefers changes
30 useEffect(() => {
31 const handler = () => setDarkMode(getPrefersScheme)
32 const matchMedia = window.matchMedia(COLOR_SCHEME_QUERY)
33
34 matchMedia.addEventListener('change', handler)
35
36 return () => {
37 matchMedia.removeEventListener('change', handler)
38 }
39 // eslint-disable-next-line react-hooks/exhaustive-deps
40 }, [])
41
42 return {
43 isDarkMode,
44 toggle: () => setDarkMode(prev => !prev),
45 enable: () => setDarkMode(true),
46 disable: () => setDarkMode(false),
47 }
48}
49
50export default useDarkMode

Usage

1import React from 'react'
2
3import { useDarkMode } from 'usehooks-ts'
4
5export default function Component() {
6 const { isDarkMode, toggle, enable, disable } = useDarkMode()
7
8 return (
9 <div>
10 <p>Current theme: {isDarkMode ? 'dark' : 'light'}</p>
11 <button onClick={toggle}>Toggle</button>
12 <button onClick={enable}>Enable</button>
13 <button onClick={disable}>Disable</button>
14 </div>
15 )
16}

See a way to make this page better?
Edit there »