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-toggleBasic 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
- First visit: Reads
prefers-color-schemefrom the browser - Toggle: Adds/removes the
darkclass on<html> - Persistence: Saves the preference to
localStorageunder keytheme - 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
| Property | Type | Default | Description |
|---|---|---|---|
| — | — | — | 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-labeldescribing 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-motionsupport