Back to elements
ElementMiscFree

Theme Toggle React component

A light / dark switch that morphs a sun into a moon, or a Light · System · Dark control with a sliding pill; it remembers the choice, follows the OS in System mode, writes the theme to <html>, and can grow the new theme out of the button in a circle.

When to use the Theme Toggle component

Use Theme Toggle in headers, footers and settings pages of any site that supports light and dark mode. The icon version fits a toolbar; the segmented version lets people pick System so the site follows their device.

Add a tiny script in <head> that applies the stored theme before paint if you want to avoid a flash on first load.

Installation

Add the Theme Toggle component to your project with the shadcn CLI. It lands in components/theme-toggle.tsx as plain React + Tailwind CSS source you own and can edit.

Install
Copied!
npx shadcn@latest add https://reactframe.com/r/theme-toggle.json

Or copy the source by hand and install its dependencies:

Install
Copied!
npm install motion clsx tailwind-merge

Props

<ThemeToggle /> accepts 10 props, all optional.

  • variant

    icon: one button that flips light / dark. segmented: Light · System · Dark.

    "icon" | "segmented"
    Default: "icon"
  • value
    "light" | "dark" | "system"
  • defaultValue
    "light" | "dark" | "system"
    Default: "system"
  • onValueChange
    (value: ThemeChoice, resolved: "light" | "dark") => void
  • apply

    Write the result to <html> (class or data-theme) and remember it. Turn off to only report changes.

    boolean
    Default: true
  • attribute
    "class" | "data-theme"
    Default: "class"
  • storageKey
    string
    Default: "theme"
  • reveal

    Grow the new theme out of the button in a circle (View Transitions, where supported).

    boolean
    Default: true
  • appearance

    Colours of the control itself.

    "dark" | "light"
    Default: "dark"
  • className
    string

FAQ

What does System do?
It follows the device's light or dark setting and updates live when that changes; the choice itself is stored as "system".
How does the circle reveal work?
In browsers with View Transitions, the new theme is revealed in a circle growing from the button. Elsewhere, or with reduced motion, it switches instantly.
Does it work with Tailwind's dark mode?
Yes. With attribute="class" it toggles the dark class on <html>, which is what Tailwind's class strategy expects; use data-theme for CSS-variable setups.

More Misc components

Share Buttons
Free
Inline Edit
Free
Social Links
Free
Terminal
Free
Scroll Progress Bar
Free
Copy Button
Free