useTernaryDarkMode()

This React Hook offers you an interface to toggle and read the dark theme mode between three values. It uses internally useLocalStorage() to persist the value and listens the OS color scheme preferences.

Returned value

  • The isDarkMode is a boolean for the final outcome, to let you be able to use with your logic.

  • The ternaryModeCode is of a literal type "dark" | "system" | "light".

    When ternaryModeCode is set to system, the isDarkMode will use system theme, like of iOS and MacOS.

    Also, ternaryModeCode implicitly exports a type with type TernaryDarkMode = typeof ternaryDarkMode

Returned interface

  • The toggleTernaryDarkMode is a function to cycle ternaryModeCode between dark, system and light(in this order).
  • The setTernaryDarkMode accepts a parameter of type TernaryDarkMode and set it as ternaryModeCode.

The Hook

1import { Dispatch, SetStateAction, useEffect, useState } from 'react'
2
3import { useLocalStorage, useMediaQuery, useUpdateEffect } from 'usehooks-ts'
4
5const COLOR_SCHEME_QUERY = '(prefers-color-scheme: dark)'
6
7type TernaryDarkMode = 'system' | 'dark' | 'light'
8interface UseTernaryDarkModeOutput {
9 isDarkMode: boolean
10 ternaryDarkMode: TernaryDarkMode
11 setTernaryDarkMode: Dispatch<SetStateAction<TernaryDarkMode>>
12 toggleTernaryDarkMode: () => void
13}
14
15function useTernaryDarkMode(): UseTernaryDarkModeOutput {
16 const isDarkOS = useMediaQuery(COLOR_SCHEME_QUERY)
17 const [ternaryDarkMode, setTernaryDarkMode] =
18 useLocalStorage<TernaryDarkMode>('usehooks-ts-ternary-dark-mode', 'system')
19 const [isDarkMode, setDarkMode] = useState<boolean>(isDarkOS)
20
21 // Update darkMode if os prefers changes
22 useUpdateEffect(() => {
23 if (ternaryDarkMode === 'system') {
24 setDarkMode(isDarkOS)
25 }
26 }, [isDarkOS])
27
28 useEffect(() => {
29 switch (ternaryDarkMode) {
30 case 'light':
31 setDarkMode(false)
32 break
33 case 'system':
34 setDarkMode(isDarkOS)
35 break
36 case 'dark':
37 setDarkMode(true)
38 break
39 }
40 }, [ternaryDarkMode, isDarkOS])
41
42 function toggleTernaryDarkMode() {
43 const toggleDict: Record<TernaryDarkMode, TernaryDarkMode> = {
44 light: 'system',
45 system: 'dark',
46 dark: 'light',
47 }
48 setTernaryDarkMode(prevMode => toggleDict[prevMode])
49 }
50
51 return {
52 isDarkMode,
53 ternaryDarkMode,
54 setTernaryDarkMode,
55 toggleTernaryDarkMode,
56 }
57}
58
59export default useTernaryDarkMode

Usage

1import { useTernaryDarkMode } from 'usehooks-ts'
2
3export default function Component() {
4 const {
5 isDarkMode,
6 ternaryDarkMode,
7 setTernaryDarkMode,
8 toggleTernaryDarkMode,
9 } = useTernaryDarkMode()
10 type TernaryDarkMode = typeof ternaryDarkMode
11
12 return (
13 <div>
14 <p>Current theme: {isDarkMode ? 'dark' : 'light'}</p>
15 <p>ternaryMode: {ternaryDarkMode}</p>
16 <p>
17 Toggle between three modes
18 <button onClick={toggleTernaryDarkMode}>
19 Toggle from {ternaryDarkMode}
20 </button>
21 </p>
22 <p>
23 Select a mode
24 <br />
25 <select
26 name="select-ternaryDarkMode"
27 onChange={ev =>
28 setTernaryDarkMode(ev.target.value as TernaryDarkMode)
29 }
30 value={ternaryDarkMode}
31 >
32 <option value="light">light</option>
33 <option value="system">system</option>
34 <option value="dark">dark</option>
35 </select>
36 </p>
37 </div>
38 )
39}

Edit on CodeSandbox

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