Pho Design System

Theme Toggle

A three-way segment for appearance — Device, Light, and Dark. Device follows prefers-color-scheme; Light / Dark force the scheme by flipping data-mode so Pho’s light-dark() tokens resolve correctly.

Import

import { ThemeToggle } from "@photon-ai/pho-ui/components/theme-toggle";

Basic

Icon-only segments in a hairline track. The selected option is the inverse chip (same language as Tabs); unselected segments carry no fill — hover only raises the icon ink. Default preference is device.

<ThemeToggle />

Sizes

Four sizes — xs, sm, md (default), lg. Use xs in dense menus.

<ThemeToggle size="xs" />
<ThemeToggle size="sm" />
<ThemeToggle />
<ThemeToggle size="lg" />

Controlled

Drive mode / onModeChange when the parent owns appearance state. Pass a target to scope the resolved scheme to a subtree — useful in previews.

Appearance

Preference: device. Scoped to this preview card.

const [mode, setMode] = useState<"device" | "light" | "dark">("device");

<ThemeToggle mode={mode} onModeChange={setMode} />;

Avoiding a flash

Persist under localStorage (pho-mode by default). Add a blocking script in <head> so the first paint already matches the stored choice:

<script>
  const mode = localStorage.getItem("pho-mode");
  const prefersDark = matchMedia("(prefers-color-scheme: dark)").matches;
  if (mode === "dark" || ((mode === "device" || mode == null) && prefersDark))
    document.documentElement.dataset.mode = "dark";
</script>

Props

Also exports getThemePreference, getThemeMode, setThemeMode, resolveThemeMode, parseThemeMode, and THEME_STORAGE_KEY.

Accessibility

Keyboard: