Theme runtime
Control light, dark, and system modes through a small store-backed controller without adding a UI provider.
Theme controller API
tsimport {
createThemeController,
mountThemeController,
subscribeTheme
} from "@tavojs/ui/theme";
export const theme = createThemeController("system");
export const stopThemeRuntime = mountThemeController(theme);
export const unsubscribeTheme = subscribeTheme(theme, (snapshot) => {
console.log(snapshot.mode, snapshot.resolvedMode);
}, { immediate: true });
export function setThemeMode(mode: "light" | "dark" | "system") {
theme.setMode(mode);
}
export function toggleThemeMode() {
theme.toggleMode();
}| API / option | Type | Default | Behavior |
|---|---|---|---|
createThemeController(mode) | ThemeController | "system" | Reads a valid saved choice, creates the state store, and exposes mode actions. |
createThemeControllerFromConfig(config) | ThemeController | config default or system | Optional convenience when browser code deliberately imports the theme config. The plugin does not pass its build-time config into runtime code. |
mountThemeController(controller) | cleanup function | — | Synchronizes the document and starts watching system preference. |
getThemeSnapshot(controller) | ThemeSnapshot | current state | Returns mode, resolvedMode, setMode, and toggleMode. |
subscribeTheme(controller, listener, options) | unsubscribe function | immediate: false | Publishes a complete snapshot after state changes. |
Mode, persistence, and system behavior
The document attribute is
data-tavo-theme. Explicit light or dark sets it; system removes it so generated media-query CSS can decide.The saved key is
tavo-ui.theme. A valid saved light, dark, or system value wins over the default passed tocreateThemeController.System resolves with
prefers-color-schemeand updates only while the selected mode remains system.toggleModechooses the explicit opposite ofresolvedMode, so it leaves system mode.Blocked or unavailable local storage does not stop theme switching.
Call both cleanup functions when the application shell unmounts or replaces the controller.