ShellUI Logo
ShellUI

Theme Toggle

Dark/light mode toggle with localStorage persistence

The ThemeToggle component provides a single-click toggle between dark and light modes. It persists the user's preference to localStorage and respects the system color scheme on first visit.

Installation

shellui add theme-toggle

Basic Usage

Drop it anywhere in your layout:

<ThemeToggle />

That's it — the component handles theme switching, persistence, and system preference detection automatically.

In a Navbar

A common placement for the theme toggle:

<Navbar>
  <a href="/" class="font-bold">MyApp</a>
  <div class="flex items-center gap-4">
    <a href="/docs">Docs</a>
    <ThemeToggle />
  </div>
</Navbar>

In a Settings Page

Include the toggle in a settings form:

<Card>
  <CardHeader>
    <CardTitle>Appearance</CardTitle>
    <CardDescription>Customize how the app looks.</CardDescription>
  </CardHeader>
  <CardContent>
    <div class="flex items-center justify-between">
      <div>
        <p class="font-medium">Dark Mode</p>
        <p class="text-sm text-muted-foreground">Toggle between light and dark themes.</p>
      </div>
      <ThemeToggle />
    </div>
  </CardContent>
</Card>

How It Works

  1. First visit: Reads prefers-color-scheme from the browser
  2. Toggle: Adds/removes the dark class on <html>
  3. Persistence: Saves the preference to localStorage under key theme
  4. Hydration: On page load, applies the saved theme before first paint to prevent flash

Theme Setup

Ensure your App.razor or _Host.cshtml includes the theme initialization script:

<script>
  (function() {
    const theme = localStorage.getItem('theme') ??
      (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
    document.documentElement.classList.toggle('dark', theme === 'dark');
  })();
</script>

API Reference

PropertyTypeDefaultDescription
No parameters required

The ThemeToggle is a self-contained component with no required parameters. It renders as an icon button that toggles between sun and moon icons.

Accessibility

The ThemeToggle component includes:

  • aria-label describing the current action ("Switch to dark mode" / "Switch to light mode")
  • Keyboard activatable via Enter and Space
  • Visible focus ring
  • Icon transition animation with prefers-reduced-motion support

On this page