Composables
useColorMode
Reactive light/dark/system color mode singleton that drives dark mode across the app.
Overview
useColorMode (from @vyui/kit) is a module-level singleton, so there is one color mode per app, shared across every call site, with no provide/inject needed.
import { useColorMode } from '@vyui/kit'
const { mode, isDark, setMode, toggle } = useColorMode()
Returns
| Property | Type | Description |
|---|---|---|
mode | Ref<'light' | 'dark' | 'system'> | The requested mode. Defaults to 'system'. Writable directly, or via setMode. |
isDark | ComputedRef<boolean> | Resolved dark state. Folds 'system' to the OS appearance: the host's theme global prop on Lynx native, matchMedia on web, light when neither is available. |
setMode | (next: ColorMode) => void | Pins an explicit mode. |
toggle | () => void | Flips between light and dark based on what's currently shown, not the mode value. Calling it while mode is 'system' pins to the opposite of whatever isDark currently resolves to, because there's no "toggle from system" state. |
The app-root contract
Binding mode and isDark only takes effect where you flow them onto the view tree. See Theming → Dark Mode for the full :class + :key contract, and reach for VyApp to get it for free.
Following the device appearance on native
In 'system' mode the OS signal comes from the host app:
- At boot, the host pushes a
theme: "light" | "dark"global prop before the template loads. - Live, the host sends a
themechangedglobal event whenever the device appearance flips.
Both are host-side wiring, and the composable picks them up automatically. Sparkling injects both signals for you; if you are building a custom host, the native host integration guide has the Swift and Kotlin snippets. Without them, 'system' resolves to light on native, so pin a mode or ship a toggle.