Skip to content
Component

Theme Toggle

A light/dark switch where the new theme sweeps across the page on a view transition.

Switches this page. The sweep rides the View Transitions API.

Installation

terminal
npx shadcn@latest add https://ui.thilina.dev/r/theme-toggle.json

Usage

Requires next-themes with the class attribute strategy:

app/layout.tsx
import { ThemeProvider } from "next-themes";

export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}
components/header.tsx
import { ThemeToggle } from "@/components/theme-toggle";

export function Header() {
  return <ThemeToggle />;
}

The incoming theme sweeps across the page on a diagonal clip-path riding the View Transitions API. The sun/moon swap is CSS-only, so the button renders correctly during SSR without a mounted check.

Props

PropTypeDefaultDescription
classNamestring-Classes merged onto the button.

Accessibility

The button carries aria-label="Switch theme" and a visible focus ring. Browsers without the View Transitions API switch instantly, and prefers-reduced-motion zeroes the sweep so the theme just flips.

Command Palette

Search for a command to run...