Theme Switcher Component β€” Astro

Accessible theme switcher with theme icons and keyboard navigation

Theme Switcher Component

The ThemeSwitcher is integrated into the Settings panel, but can also be used standalone.

Live Example

Try switching themes using the theme switcher below:

Usage

astro astro
---
import ThemeSwitcher from '../../components/ThemeSwitcher.astro';
---

<ThemeSwitcher />

Features

The theme switcher:

  • Preference (System) – Choose System to follow OS light/dark; theme updates when you change the OS preference.
  • Preview panel – Always visible when the menu is open (on viewports >480px). Shows a fixed β€œPreview” label; the theme name, swatch, and accent bar show the current theme by default and the hovered theme on hover/focus. Full-height divider between list and preview. Hidden on small viewports.
  • Groups themes by Preference, Dark, and Light; each theme has a unique icon.
  • Shows active theme name and icon in the trigger button.
  • Consistent width – The trigger and dropdown use a fixed width (--theme-switcher-width) everywhere (Settings, navbar, standalone) so the longest theme name fits on one line.
  • When System is selected, both System and the applied theme show the active background and accent bar.
  • Persists selection in localStorage (key theme: theme id or system).
  • First visit uses initial data-theme or OS preference.
  • Full keyboard navigation (see below).

Keyboard Navigation

  • Enter or Space - Open/close menu
  • ArrowDown - Open menu and focus first option
  • ArrowUp - Open menu and focus last option
  • ArrowDown/ArrowUp - Navigate options within menu
  • Home - Jump to first option
  • End - Jump to last option
  • Enter or Space - Select theme
  • Escape - Close menu
  • Tab - Close menu and continue tabbing

Building your own theme switcher

All 14 themes are included in the Rizzo CSS bundle. Switching themes is done by setting data-theme on <html> and persisting the choice in localStorage (key theme). You can use the ThemeSwitcher component above, or build a custom UI with the same behavior.

Theme utilities (see Getting Started – JavaScript utilities):

  • applyTheme(value) – Sets data-theme and saves to localStorage. Use a theme id (e.g. github-dark-classic) or system to follow OS light/dark. Dispatches rizzo-theme-change.
  • getThemeLabel(value) / getThemeInfo(value) – Display names for theme ids and for system.
  • getStoredTheme() – Current stored value (theme id or system).
  • resolveSystemTheme() – Resolves OS preference to a concrete theme id (dark β†’ GitHub Dark Classic, light β†’ GitHub Light).
  • Constants: THEME_SYSTEM, DEFAULT_THEME_DARK, DEFAULT_THEME_LIGHT.

Theme IDs: Run npx rizzo-css theme to list all 14 ids, or see Theming – Available themes. To sync a custom UI when the theme changes elsewhere, listen for the rizzo-theme-change event.

ThemeIcon: To show the same icon as the switcher elsewhere (e.g. theme pages, cards), use Astro <ThemeIcon themeId="github-dark-classic" size=24 /> or Svelte <ThemeIcon themeId="github-dark-classic" size=24 />. Props: themeId, optional size (default 24), optional class. Vanilla: use the icon SVGs from the Icons section and map theme id to icon via themes.ts iconKey.

Svelte & Vanilla: Svelte (live Svelte component) Β· Vanilla (live example + copyable HTML). Or use theme utilities (applyTheme, getThemeLabel) and see Building your own theme switcher.