Theme Switcher

A light/dark/system theme toggle. Comes in two variants: a dropdown listing all three options and a compact icon-only toggle. Requires next-themes ThemeProvider in the root layout.

Dropdown (left) · Icon toggle (right)

import { ThemeSwitcher } from "@aetherstack/patterns"

Installation

terminal
npx aether-ui add theme-switcher

Import

import.tsx
import { ThemeSwitcher, ThemeSwitcherToggle, ThemeSwitcherDropdown } from "@aetherstack/patterns"

Usage

theme-switcher.tsx
// In layout.tsx — wrap the app with ThemeProvider
import { ThemeProvider } from "next-themes"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html suppressHydrationWarning>
      <body>
        <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}

// In your navigation bar
import { ThemeSwitcherDropdown, ThemeSwitcherToggle } from "@aetherstack/patterns"

export function Navbar() {
  return (
    <nav>
      {/* compact icon-only toggle */}
      <ThemeSwitcherToggle />

      {/* or a dropdown with light / dark / system options */}
      <ThemeSwitcherDropdown />
    </nav>
  )
}

Props

PropTypeDefaultDescription
ThemeSwitcherDropdown and ThemeSwitcherToggle take no required props. They read and write the active theme via next-themes internally.
classNamestringAdditional classes on the trigger button (both variants).

* Required

Accessibility

  • Each button carries an aria-label describing the action ("Toggle theme" or the active theme name).
  • The dropdown uses role="menu" with radio-style aria-checked items for each theme option.
  • Active theme is communicated via aria-checked="true" on the selected menu item.
  • Icons are aria-hidden; labels are the sole source of accessible name.