Skip to main content

useDarkMode

dark mode with auto data persistence.

⚠️ 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
Migration Guide

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.

Tips

click to open

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.
<script
dangerouslySetInnerHTML={{
// add a self-executing function
__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 {
// Handle backward compatibility: convert old boolean values to string
if (store === 'true' || store === 'false') {
const boolValue = store === 'true';
const stringValue = boolValue ? 'dark' : 'light';
localStorage.setItem('reactuses-color-scheme', stringValue);
dark = boolValue;
} else {
// Handle string value ('dark' or 'light') directly
dark = store === 'dark';
}
}
setDark(dark)
})();
`,
}}
></script>
  1. To conveniently manage theme colors in a unified way, we recommend using context to store them.
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;
}

Usage

Live Editor
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>
  );
};

Result
theme: light

API

UseDarkOptions

PropertyDescriptionTypeDefaultValue
selectorCSS Selector for the target element applying tostring'html'
attributeHTML attribute applying the target elementstring'class'
defaultValuedefault valuebooleanfalse
storageKeyKey to persist the data into localStorage/sessionStorage.string'reactuses-color-scheme'
storageStorage object, can be localStorage or sessionStorage() => StoragelocalStorage
classNameDarkname dark apply to elementstring (Required)-
classNameLightname light apply to elementstring (Required)-

useDarkMode

Returns

readonly [boolean | null, () => void, React.Dispatch<React.SetStateAction<boolean | null>>]: A tuple with the following elements:

  • The current value of the dark state.
  • A function to toggle the dark state.
  • A function to update the dark state.

Arguments

ArgumentDescriptionTypeDefaultValue
options-UseDarkOptions (Required)-
Squarespace
Squarespace can simplify your workflow, making reviewing projects, sending documents, and getting paid a breeze.
Get Started