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

Usage

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

Edit on CodeSandbox

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