Limited offer: $250 off for the first 200 customers!Claim discount

Theme Toggle

A toggle switch that flips between light and dark mode and persists the choice to localStorage.

How it works

ThemeToggle is a client component. On first render it reads the current data-theme attribute from <html> to determine the initial state — no flash, no hydration mismatch. When clicked, it writes the new theme name to both document.documentElement.setAttribute('data-theme', ...) and localStorage so the preference survives page reloads.

The toggle uses the values of config.lightTheme and config.darkTheme— it does not hardcode "light" and "dark". If you rename your themes, update those two fields and the toggle will follow.

Usage

import ThemeToggle from "@/components/ThemeToggle";

<ThemeToggle />

The component is already placed in Header and is shown or hidden by the enableThemeToggle flag in config.ts. You can also drop it anywhere else — a settings page, a footer, a mobile menu.

Config options

  • enableThemeToggle — set to false to hide the toggle from the header entirely. The component itself still works if you place it manually.
  • lightTheme — the DaisyUI theme name applied when the user switches to light mode. Defaults to "light".
  • darkTheme — the DaisyUI theme name applied when the user switches to dark mode. Defaults to "dark".
// src/config.ts
enableThemeToggle: true,
lightTheme: "light",
darkTheme: "dark",

The values must be valid DaisyUI theme names. Any built-in theme works (cupcake, forest, night, etc.). You can also use a custom theme defined in your CSS — just make sure the name matches what you pass to data-theme.

TipThe initial state is read from the DOM, not from localStoragedirectly. That's intentional — the layout sets data-theme server-side from a cookie so there is no flash of the wrong theme on load. Do not read localStorage in a useState initializer or you will get a hydration mismatch in Next.js.