Morpha UI

Theme Toggle

An icon button that flips between light and dark with a circular reveal.

Overview

ThemeToggle is an IconButton wired to next-themes. Clicking it flips the theme between light and dark; on browsers that support the View Transitions API the change plays as an expanding circle wiped out from the button, and everywhere else it falls back to an instant swap. The Sun/Moon glyph always crossfades with a subtle scale and blur.

It inherits IconButton's geometry, state layers and focus ring, so variant, size and shape pass straight through — it defaults to the low-emphasis standard style.

$ npx morpha-ui add theme-toggle

Examples

Variants

Because it forwards to IconButton, every button style is available. Use standard for a bare toolbar icon, or a contained style when it needs more presence.

Sizes

The square IconButton sizes apply here too.

Usage

ThemeToggle reads the theme from a next-themes provider, so it must render inside one. In this Fumadocs site that provider is already supplied by RootProvider; in a plain Next.js app, wrap your tree once at the root:

import { ThemeProvider } from "next-themes";
import { ThemeToggle } from "@/components/ui/theme-toggle";

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
      <header>
        <ThemeToggle />
      </header>
      {children}
    </ThemeProvider>
  );
}

Add suppressHydrationWarning to your <html> element, as next-themes requires.

Installation

Morpha UI components are distributed via the Morpha CLI (coming in a later step): npx morpha-ui add theme-toggle. It depends on icon-button, next-themes and motion.

API Reference

Prop

Type

Accessibility

  • Renders a native <button> via IconButton, so keyboard activation and focus handling come for free.
  • Ships a default aria-label of "Toggle theme"; override it to match your wording or locale.
  • A static placeholder with the same footprint renders until mount, avoiding a hydration mismatch and layout shift.
  • The circular reveal is skipped where it can't play reliably (no View Transitions support, or macOS); the theme still changes.
  • The icon crossfade keeps its opacity change under prefers-reduced-motion.

On this page