---
title: "useDarkMode – Browser Hook Usage & Examples"
description: "Dark mode with auto data persistence."
canonical: https://reactuse.com/browser/usedarkmode/
---

# useDarkMode

dark mode with auto data persistence.

`useDarkMode` provides a simple dark/light mode toggle with automatic persistence to `localStorage`. It returns a tuple of the current theme state and a toggle function. The hook applies CSS class names (configurable as `classNameDark` and `classNameLight`) to the `<html>` element and syncs with the user's system preference via the `prefers-color-scheme` media query when no stored value exists. It respects the system preference as a default but allows the user to override it.

### When to Use

- Adding a dark mode toggle to your application with automatic persistence
- Building a theme switcher that respects the user's system color scheme preference as a default
- Applying dark/light CSS classes to the root element for CSS-driven theming

### Notes

- **SSR-safe**: Returns `false` for the dark mode state during server-side rendering. No DOM or localStorage access occurs on the server. See the Tips section below for preventing flash of unstyled content.
- **Persistence**: Stores the preference in `localStorage` under the key `"reactuses-color-scheme"`. The stored value is automatically migrated from the old boolean format to the new string format in v6.1.0+.
- **Related hooks**: For multi-theme support beyond dark/light, see `useColorMode`. For detecting the system preference without persistence, see `usePreferredDark` or `usePreferredColorScheme`.

## Breaking Change in v6.1.0

**Storage format has changed from boolean to string values.** If you're upgrading from a previous version:

- **Old format**: `true`/`false` boolean values
- **New format**: `"dark"`/`"light"` string values
- **Auto-migration**: Existing data will be automatically migrated
- **SSR scripts**: Need to be updated to handle string comparisons

<details>
<summary>Migration Guide</summary>

If you have custom SSR scripts, update them as shown in the examples below. The library handles data migration automatically, but your custom scripts need to handle both old and new formats during the transition period.

</details>

## Tips

<details>
<summary>click to open</summary>

For server-side rendered applications, since it's not possible to obtain the user's color preference on the server side, there might be a flicker during the first render. To avoid this issue, you can refer to the following steps.

1. add a script before your content.

```tsx
<script
  dangerouslySetInnerHTML={{
    __html: `
          (function () {
            function setDark(dark) {
              dark &&  document.documentElement.classList.add('dark');
            }
            let store = localStorage.getItem('reactuses-color-scheme');
            let dark;
            if(store === null){
              const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');
              dark = darkQuery.matches;
            }else {
              if (store === 'true' || store === 'false') {
                const boolValue = store === 'true';
                const stringValue = boolValue ? 'dark' : 'light';
                localStorage.setItem('reactuses-color-scheme', stringValue);
                dark = boolValue;
              } else {
                dark = store === 'dark';
              }
            }
            setDark(dark)
          })();
      `,
  }}
></script>
```

2. To conveniently manage theme colors in a unified way, we recommend using context to store them.

```tsx
import { useDarkMode } from "@reactuses/core";
import React, { createContext, useContext } from "react";

type ThemeContext = { theme: boolean; toggleTheme: () => void };

const ThemeContext = createContext<ThemeContext | undefined>(undefined);

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [dark, toggle] = useDarkMode({
    classNameDark: "dark",
    classNameLight: "light",
    defaultValue: false,
  });

  return (
    <ThemeContext.Provider value={{ theme: !!dark, toggleTheme: toggle }}>
      {children}
    </ThemeContext.Provider>
  );
}

export function useTheme() {
  const context = useContext(ThemeContext);
  if (context === undefined) {
    throw new Error("useTheme must be used within a ThemeProvider");
  }
  return context;
}
```

</details>

## Usage

```tsx live
function Demo() {
  const [theme, toggleDark] = useDarkMode({
    classNameDark: "dark",
    classNameLight: "light",
    defaultValue: false,
  });

  return (
    <div>
      <div>theme: {theme ? "dark" : "light"}</div>
      <br />
      <div>
        <button onClick={toggleDark}>toggleDark</button>
      </div>
    </div>
  );
}
```

%%API%%