API Reference
@themvora/nuxt
Nuxt 4 module with SSR-first theming, zero-flash bootstrap, cookie sync and auto-imported composables.
The Nuxt module wires auto-imported useTheme* composables, the
ThemeScope / ThemeScrollbar / ThemeInspector components, and the
server-side cookie + bootstrap helpers (defineNuxtTheme,
resolveThemeFromCookies, NuxtThemeBootstrap).
Generated from
packages/nuxt/srcbyapps/docs/scripts/generate-api-reference.mjs. Do not edit by hand — runpnpm --filter @themvora/docs api:generate.
Functions
auditActionProminence(theme): ActionProminence
Measure whether a theme's action fill reads as a control.
Why this is a third contract, not a fourth context
- semantic pair —
primaryagainstprimaryForegroundmust be readable. - context — where each role may be used, and with whose judgement.
- prominence — a generated fill must separate from the canvas, because a fill that does not has stopped reading as a control.
It cannot be expressed as "primary must clear X:1 against background"
globally, because that would condemn every dark brand anchor. Hence the
anchored flag: the invariant binds generated fills and merely reports
anchored ones — Slack's aubergine is 1.42:1 against the dark canvas, and that
is the brand being the brand.
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme to measure. |
Returns ActionProminence — The measurement, with anchored telling the caller which rule applies.
auditSemanticContexts(theme): ContextResult[]
Evaluate every declared context against a theme.
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme to check. |
Returns ContextResult[] — One result per context, in declaration order.
auto(tokenName, lookup): string
Resolve an auto() foreground token by deriving its value from a base color
token.
Given a token name ending in Foreground/foreground (or Fg), the base
token is looked up via the provided resolver and its contrast foreground is
returned. When the base color cannot be resolved, #000000 is returned.
| Parameter | Type | Description |
|---|---|---|
tokenName | string | The foreground token name to derive (e.g. "primaryForeground"). |
lookup | __type(path: string): string | undefined | A resolver that maps a dot-path token key to its value. |
Returns string — A black or white foreground color string.
buildThemeCssMap<T extends ThemeDefinition<string>>(themes, options?): Record<string, Record<string, string>>
Build a lookup map of theme keys to flat CSS variables.
Each theme is registered twice:
- under its own
name(e.g."sunrise-light") - under a
family:modekey (e.g."sunrise:light") so that a persisted family + effective mode can be resolved without knowing theme names.
See also: createThemeBootstrapScript
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | — |
options | BuildThemeCssMapOptions (optional) | — |
Returns Record<string, Record<string, string>>
calculateSunTimes(date, args...): SunTimes
Compute today's sunrise and sunset using the standard NOAA solar algorithm (zenith-based, corrected for the equation of time and for longitude).
latitude and longitude are optional: when omitted (or when an options
object is passed instead), the location is resolved from timeZone or the
visitor's browser timezone via resolveSolarLocation. Passing neither
coordinates nor a timezone means every visitor gets sunrise/sunset for their
own location automatically.
// Explicit coordinates (unchanged behavior).
calculateSunTimes(date, 48.8566, 2.3522);
// Resolve from the visitor's timezone.
calculateSunTimes(date);
// Resolve from an explicit timezone.
calculateSunTimes(date, { timeZone: "Asia/Kathmandu" });| Parameter | Type | Description |
|---|---|---|
date | Date | The day to compute for. Its local calendar date is used. |
| ...args | [latitude: number, longitude: number, options: SolarLocationInput] | [options: SolarLocationInput] | latitude, longitude[, options], or an options bag. |
Returns SunTimes — The sunrise/sunset pair as absolute instants (see SunTimes).
The local-clock contract. Both returned Dates are absolute instants
computed from the location's longitude and the day's solar declination. Their
local representation is therefore the correct wall-clock time for that day,
and it follows daylight-saving transitions because it is derived from the
real UTC instant rather than from a fixed offset.
Longitude matters. Solar noon at a location occurs at
720 - 4·longitude - eqTime minutes UTC (east-positive longitude), and
sunrise/sunset sit ±4·hourAngle minutes either side of it. Treating that
result as local clock time — which the previous implementation did, because
it never applied the longitude term — put the switch at the wrong hour
wherever the local time-zone meridian differs from the location's longitude.
timeZone resolves coordinates, not the clock. It is used only to pick
the latitude/longitude pair; the returned instants are read on the host's own
clock. This API therefore does not support computing "sunrise in Tokyo" on a
server in London: the coordinates would be Tokyo's but the day boundary and
the displayed wall-clock time would be the server's. Pass explicit
coordinates for the visitor's location, or run the calculation in the
visitor's browser.
Polar day and polar night are reported through SunTimes.polar.
The hour-angle formula has no solution when the sun stays above or below the
horizon, and the previous implementation clamped cosH into [-1, 1],
which produced a zero-length day: sunrise equal to sunset, so the
daytime test was never true and a polar-day visitor got the dark theme at
noon.
cancelThemeAnimation(target): void
Abort any in-flight theme animation for target and remove its styles.
| Parameter | Type | Description |
|---|---|---|
target | HTMLElement | — |
Returns void
chooseForeground(role, background, ctx): Oklch
Choose the foreground for a role on a surface.
if the preferred ink meets the target: use it
else if the other ink meets it: use that
else: use the better of the two, and let the solver repair itWhy the target, and not the floor
The internal target (4.75) is used here rather than the published floor (4.5), because that is what makes the preference free: whenever the preferred ink clears 4.75 it is also the higher-ratio ink, so honouring the preference and maximising contrast agree. The two rules only diverge in the narrow band where white measures 4.50–4.58, and there the fallback takes the higher ratio.
This is why the change is a refactor rather than a behaviour change for
existing themes — see the note in theme-generation.md. What it buys is that
the rule is now explicit, per-role and testable, instead of being an
emergent property of a >= comparison inside bestInk.
| Parameter | Type | Description |
|---|---|---|
role | CoreColor | The foreground role being generated. |
background | Oklch | The surface it will sit on. |
ctx | PaletteContext | The generation context. |
Returns Oklch — The chosen ink.
clearMigrations(): void
Remove all registered migration steps, resetting the migration system to an empty state.
Returns void
composeTheme<TName extends string>(name, sources...): ThemeDefinition<TName>
Compose a theme by layering multiple sources (e.g. a family theme, a mode override, and local tokens), later sources winning.
See also: mergeThemeDefinitions, defineTheme
| Parameter | Type | Description |
|---|---|---|
name | TName | — |
| ...sources | ThemeDefinition<string>[] | — |
Returns ThemeDefinition<TName>
computeFingerprint(themes, defaultTheme?): string
Fingerprints a theme registry so a persisted selection from an older build —
different themes, or a different defaultTheme — is ignored rather than
applied against themes it was never valid for.
See also: ThemeBootstrapCookieSource, buildBootstrapPlan
| Parameter | Type | Description |
|---|---|---|
themes | readonly ThemeDefinition<string>[] | The theme registry to fingerprint. |
defaultTheme | string (optional) | The fallback theme name. Included in the fingerprint, so changing it invalidates previously persisted selections. |
Returns string — A stable fingerprint string, or "" when themes is empty.
The result is written to the theme-fingerprint cookie and compared on the
next request, so it is part of the stable cookie contract documented in
VERSIONING.md — changing the format invalidates every visitor's persisted
selection on their next visit.
It lives here, in core, because four SSR integrations (Next, Nuxt, Astro, Remix) previously each carried a byte-identical private copy. Any edit to one of them would have silently broken cross-framework persistence with nothing to catch it.
contextFailures(theme): { advisory: ContextResult[]; required: ContextResult[] }
The contexts a theme fails, split by whether the generator promised them.
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme to check. |
Returns { advisory: ContextResult[]; required: ContextResult[] } — required failures are bugs; advisory failures are declared gaps.
contrast(background): string
Compute a readable foreground color for a given background color.
Returns #000000 when the background is light enough (relative luminance
above 0.179), otherwise #ffffff. Accepts a hex color with or without the
leading #; non-hex input falls back to #000000.
| Parameter | Type | Description |
|---|---|---|
background | string | The background color to contrast against. |
Returns string — A black or white foreground color string.
createAccessibilityPlugin<T extends ThemeDefinition<string>>(options?): ThemePlugin<T>
Creates a plugin that validates theme contrast for accessibility.
The plugin runs a WCAG contrast check on the active theme after every theme
change and reports any violations that fail AA normal contrast, either by
emitting a TV_A11Y_CONTRAST_VIOLATION diagnostic or by invoking the
onViolation callback.
See also: AccessibilityPluginOptions
| Parameter | Type | Description |
|---|---|---|
options | AccessibilityPluginOptions (optional) | Accessibility configuration. |
Returns ThemePlugin<T> — An "accessibility" theme plugin.
Violations are reported only when the theme fails AA normal contrast and at
least one check fails. warnOnly chooses the diagnostic's level. The failing
checks travel as the diagnostic's structured context, so they stay available
to the console and to any consumer of the diagnostics stream rather than
being flattened into the message.
const manager = createPluginManager();
manager.use(createAccessibilityPlugin({
warnOnly: true,
onViolation: ({ themeName, checks }) => report(themeName, checks),
}));createAdapterRegistry<T extends ThemeDefinition<string>>(runtime): AdapterRegistry<T>
Create the runtime-owned adapter registry for a theme runtime.
Registering an adapter installs it; the registry tracks reference counts so
composition (React Strict Mode, Svelte lifecycles, nested providers) is
deterministic. use is idempotent per adapter instance and returns an
AdapterRegistration whose dispose() uninstalls exactly that instance
when its own reference count drops to zero. Registering a different adapter
instance under an already-used id replaces the previous one.
| Parameter | Type | Description |
|---|---|---|
runtime | ThemeRuntime<T> | The theme runtime the adapters are installed into. |
Returns AdapterRegistry<T> — The adapter registry bound to runtime.
const registry = createAdapterRegistry(runtime);
const handle = registry.use(adapter);
// ... later
handle.dispose();createAnimationsPlugin<T extends ThemeDefinition<string>>(options?): ThemePlugin<T>
Creates a plugin that animates theme changes with CSS transitions.
The plugin applies a CSS transition to the target element before a theme change so the resulting token updates animate smoothly, and removes the transition when the plugin is destroyed.
See also: AnimationsPluginOptions
| Parameter | Type | Description |
|---|---|---|
options | AnimationsPluginOptions (optional) | Animation configuration. |
Returns ThemePlugin<T> — An "animations" theme plugin.
The plugin opts out of View Transitions by default; it provides CSS
transition properties rather than page-level crossfades. onDestroy removes
the transition from the target element.
const manager = createPluginManager();
manager.use(createAnimationsPlugin({ transition: { duration: 500 } }));createBroadcastPlugin<T extends ThemeDefinition<string>>(options?): ThemePlugin<T>
Creates a plugin that synchronizes the theme selection across browser tabs and windows.
The plugin subscribes to incoming selection messages when the runtime is
created and applies the received mode/family to the runtime, and broadcasts
the selection after every persist. It uses a BroadcastChannel-based
adapter by default when available.
See also: BroadcastPluginOptions
| Parameter | Type | Description |
|---|---|---|
options | BroadcastPluginOptions (optional) | Broadcast configuration. |
Returns ThemePlugin<T> — A "broadcast" theme plugin.
onDestroy unsubscribes from incoming messages and closes the default
channel. When no adapter is available the plugin is inert.
const manager = createPluginManager();
manager.use(createBroadcastPlugin({ channelName: "my-app-theme" }));createCSSVariablesBinding(store, options?): { destroy: void; setTransition: void } | null
Create a binding that keeps CSS custom properties (--theme-*) on a
target element (default <html>) in sync with the store. Applies the
current theme immediately on creation and diffs updates.
See also: themeToCSSVariables, CSSVariablesOptions
| Parameter | Type | Description |
|---|---|---|
store | ThemeStore | — |
options | CSSVariablesOptions (optional) | — |
Returns { destroy: void; setTransition: void } | null
createDebuggerPlugin<T extends ThemeDefinition<string>>(options?): ThemePlugin<T>
Creates a plugin that logs theme runtime activity to the console.
The plugin logs theme changes, active theme tokens, and persistence events (before and after) to the console, gated by the corresponding options.
See also: DebuggerPluginOptions
| Parameter | Type | Description |
|---|---|---|
options | DebuggerPluginOptions (optional) | Debugger configuration. |
Returns ThemePlugin<T> — A "debugger" theme plugin.
const manager = createPluginManager();
manager.use(createDebuggerPlugin({ label: "[my-app]" }));createDefaultPersistence(): ThemeSelectionPersistenceAdapter | null
Creates the default persistence adapter: a localStorage-backed
selection adapter under the "theme-selection" key.
Returns null when window is unavailable (SSR) or storage access
throws. Cross-tab changes are surfaced through the storage event.
See also: ThemeSelectionPersistenceAdapter, createThemePersistence
Returns ThemeSelectionPersistenceAdapter | null — A persistence adapter, or null when storage is unavailable.
createDevToolsPlugin<T extends ThemeDefinition<string>>(options?): ThemePlugin<T>
Creates a plugin that exposes the theme runtime to browser devtools.
When enabled, the plugin registers a devtools hook on window that exposes
the current themes, selection, active theme, and history, so a devtools
extension can inspect the runtime state.
See also: DevToolsPluginOptions
| Parameter | Type | Description |
|---|---|---|
options | DevToolsPluginOptions (optional) | Devtools configuration. |
Returns ThemePlugin<T> — A "devtools" theme plugin.
The hook is only registered in browser environments. onDestroy clears the
internal runtime reference.
Entries are added to the same window.__THEMVORA_DEVTOOLS__ set that
@themvora/devtools's inspector plugin uses, and must satisfy that set's
declared shape — getState(), getEntries(), getPerformance(). This
plugin records no entries or performance samples, so those two return empty
arrays; the point is that a consumer enumerating the set can call all three
on every member without a type check. Use
@themvora/devtools's createDevToolsPlugin instead when you want the
recorded entries and timings.
const manager = createPluginManager();
manager.use(createDevToolsPlugin());createDiagnostic(input): ThemeDiagnostic
Create a ThemeDiagnostic.
Pure: no console access, no environment reads, no deduplication. The docs
link is derived from the code so call sites never repeat it.
See also: emitDiagnostic
| Parameter | Type | Description |
|---|---|---|
input | CreateDiagnosticInput | The diagnostic fields. |
Returns ThemeDiagnostic — A diagnostic value. Creating one has no side effects.
const diagnostic = createDiagnostic({
code: "TV_MODE_INVALID",
level: "warning",
message: 'setMode() received an unknown mode "purple".',
context: { api: "setMode", property: "mode", received: "purple", expected: "light | dark | system" },
hint: "Pass one of the three valid modes, or omit the call.",
});createDOMBinding(store, options?): { apply: __type(theme: ThemeDefinition, emitOptions?: { suppressTransition?: boolean }): void; destroy: void; setTransition: void } | null
Create a binding that syncs the store theme to the DOM: data-theme,
data-theme-mode, data-theme-family, the dark class, and the
color-scheme style — with transition support.
See also: DOMBindingOptions, createCSSVariablesBinding
| Parameter | Type | Description |
|---|---|---|
store | ThemeStore | — |
options | DOMBindingOptions (optional) | — |
Returns { apply: __type(theme: ThemeDefinition, emitOptions?: { suppressTransition?: boolean }): void; destroy: void; setTransition: void } | null
createGenerationPlugin<T extends ThemeDefinition<string>>(options?): GenerationPlugin<T>
Creates a plugin that participates in theme generation.
The plugin is inert until GenerationPlugin.generate is called: it
registers no tokens of its own and its transformTokens hook is the identity.
Generating goes through generateTheme, so the plugin and the runtime cannot
disagree about what a seed produces.
See also: GenerationPluginOptions
| Parameter | Type | Description |
|---|---|---|
options | GenerationPluginOptions (optional) | Default seed, default generation options, and a hook. |
Returns GenerationPlugin<T> — A "theme-generation" plugin with a generate method.
const plugin = createGenerationPlugin({ seed: "#6366f1" });
const { light, dark } = plugin.generate({ family: "brand", style: "brand" });createHistoryPlugin<T extends ThemeDefinition<string>>(options?): ThemePlugin<T>
Creates a plugin that configures the runtime's theme history.
The plugin applies the given history options (notably maxSteps) to the
runtime's history when the runtime is created.
See also: HistoryPluginOptions
| Parameter | Type | Description |
|---|---|---|
options | HistoryPluginOptions (optional) | History configuration. |
Returns ThemePlugin<T> — A "history" theme plugin.
const manager = createPluginManager();
manager.use(createHistoryPlugin({ maxSteps: 20 }));createMultiWindowSync(options?): ThemeSelectionBroadcastAdapter
Sync theme selection across browser tabs/windows via BroadcastChannel (with a SharedWorker + storage fallback).
| Parameter | Type | Description |
|---|---|---|
options | MultiWindowSyncOptions (optional) | — |
Returns ThemeSelectionBroadcastAdapter
createNoopSync(): ThemeSelectionBroadcastAdapter
Create a no-op theme-selection sync adapter.
Every method is a safe no-op: post discards the value, subscribe
returns an unsubscribe that does nothing, and destroy does nothing. Used
as the final fallback when no cross-tab strategy is available.
Returns ThemeSelectionBroadcastAdapter — A ThemeSelectionBroadcastAdapter that performs no synchronization.
createNuxtThemeBootstrapScript<T extends ThemeDefinition<string>>(options): string
Generate the blocking, inline bootstrap script that applies the persisted
theme before first paint — the same zero-flash guarantee @themvora/next
ships.
The script reads the four theme cookies (same contract as Next), validates
the config fingerprint, resolves the theme for the effective mode
("system" is resolved against prefers-color-scheme), and writes the CSS
variables plus DOM effects onto document.documentElement. It delegates to
the shared @themvora/core applier (buildBootstrapPlan +
serializeThemeBootstrapScript), so every SSR integration emits the same
correct script and cannot drift from the client runtime contract.
Emit it in <head> with tagPriority: "critical" so it runs before the app
stylesheets and the browser paints already themed.
See also: NuxtThemeBootstrapOptions, resolveThemeFromCookies
| Parameter | Type | Description |
|---|---|---|
options | NuxtThemeBootstrapOptions<T> | — |
Returns string
createOverlayScrollbar(store, options?): OverlayScrollbarHandle | null
Framework-agnostic, theme-aware scrollbar overlay engine.
The browser performs all scrolling — this only renders + animates a visual overlay that tracks it, so inertia, touch, wheel, keyboard and accessibility remain native. Colors come from Themvora tokens, so the overlay re-themes with the rest of the app (no flashes). It tracks the document plus every scrollable element on the page by default (anywhere a native scrollbar would appear); the native track is hidden automatically — no manual CSS required.
| Parameter | Type | Description |
|---|---|---|
store | ThemeStore | — |
options | OverlayScrollbarOptions (optional) | — |
Returns OverlayScrollbarHandle | null
createPersistencePlugin<T extends ThemeDefinition<string>>(options?): ThemePlugin<T>
Creates a plugin that persists the theme selection and restores it on startup.
The plugin reads the saved selection when the runtime is created (if
readOnInit is enabled) and writes the selection to the adapter after every
persist. It uses a localStorage-backed adapter by default in the browser
and is inert in non-browser environments unless a custom adapter is given.
See also: PersistencePluginOptions
| Parameter | Type | Description |
|---|---|---|
options | PersistencePluginOptions (optional) | Persistence configuration. |
Returns ThemePlugin<T> — A "persistence" theme plugin.
The default adapter also subscribes to cross-tab storage events so the
selection stays in sync across tabs. onDestroy releases the adapter and
runtime references.
const manager = createPluginManager();
manager.use(createPersistencePlugin({ key: "my-app-theme" }));createPluginManager<T extends ThemeDefinition<string>>(): PluginManager<T>
Creates a PluginManager for registering and coordinating theme plugins.
The returned manager stores plugins by name, orders them by ascending
priority (default 10) for hook dispatch, and coordinates destruction.
See also: PluginManager, ThemePlugin
Returns PluginManager<T> — A new, empty plugin manager.
Registering a plugin whose name is already present is skipped with a
console warning and returns a no-op disposer. destroy invokes onDestroy
on every plugin (in priority order) and clears the registry.
destroy is failure-isolated: a plugin whose onDestroy throws is reported
with TV_PLUGIN_DESTROY_FAILED and the remaining plugins are still
destroyed, so one broken plugin cannot leak the rest.
const manager = createPluginManager<MyTheme>();
const dispose = manager.use(createPersistencePlugin());
manager.list(); // [persistence plugin]
dispose(); // removes itcreatePrePaintScrollbarCSS(): string
The hiding CSS, for SSR output (e.g. Next inlines it as a <style> in
<head>). Use together with the tv-scrollbar class on <html>.
Returns string
createPrePaintScrollbarScript(options?): string
Generate a blocking <script> that hides the native scrollbar before
first paint. The script is idempotent — calling it multiple times is safe.
On coarse-pointer devices it returns early (unless touch is forced), so
native scrollbars are kept.
| Parameter | Type | Description |
|---|---|---|
options | PrePaintScrollbarOptions (optional) | — |
Returns string
createProvidedThemesSource<T extends ThemeDefinition<string>>(runtime): ProvidedThemesSource<T>
Create a reactive source over one provider's theme collection.
The derivation runs once per settled change to the provider's registry and is cached in between, so:
- the returned array is referentially stable while nothing changes,
- a
register/unregister/use/configureis reflected on the next read, - two providers never share a collection.
See also: normalizeProvidedThemes
| Parameter | Type | Description |
|---|---|---|
runtime | ProvidedThemesRuntime<T> | The provider's runtime. |
Returns ProvidedThemesSource<T> — A source with get() and subscribe().
const source = createProvidedThemesSource(runtime);
source.subscribe(() => console.log(source.get().length));createScheduledPlugin<T extends ThemeDefinition<string>>(options): ThemePlugin<T>
Creates a plugin that switches the theme selection by time of day.
The plugin resolves a light/dark theme pair and installs a scheduled theme binding that applies the appropriate theme based on the visitor's local sunrise/sunset times. It re-resolves the pair when the theme family changes so auto-derived themes follow the current selection.
See also: ScheduledPluginOptions
| Parameter | Type | Description |
|---|---|---|
options | ScheduledPluginOptions<T> | Schedule configuration. |
Returns ThemePlugin<T> — A "scheduled" theme plugin.
When the light/dark pair cannot be resolved, the plugin emits a
TV_SCHEDULE_THEME_UNRESOLVED diagnostic and does not install a binding.
onDestroy destroys the binding, unsubscribes from the store, and clears all
internal state.
const manager = createPluginManager();
manager.use(createScheduledPlugin({
lightTheme: "day",
darkTheme: "night",
timeZone: "Asia/Kathmandu",
}));createScheduledThemeBinding<T>(store, options): { destroy: void; getEnabled: void; getLocation: void; setEnabled: void; setLastSyncTime: void }
Create a scheduled theme binding that applies a light theme during daytime and a dark theme at night.
The binding resolves a location (explicit coordinates, an explicit
timeZone, or browser auto-detection), computes sunrise/sunset, applies
the matching theme immediately, and re-checks on checkInterval. It can be
toggled at runtime via setEnabled and stopped via destroy (which is
idempotent and clears the timer).
See also: ScheduledThemeBindingOptions
| Parameter | Type | Description |
|---|---|---|
store | { get: void; set: void } | The store the scheduled theme is applied to. |
options | ScheduledThemeBindingOptions<T> | The scheduled-binding configuration. |
Returns { destroy: void; getEnabled: void; getLocation: void; setEnabled: void; setLastSyncTime: void } — A controller exposing destroy, setLastSyncTime, setEnabled,
getEnabled and getLocation.
const binding = createScheduledThemeBinding(store, {
lightTheme,
darkTheme,
timeZone: "Asia/Kathmandu",
});
// ... later
binding.destroy();createScopedThemeBinding<T extends ThemeDefinition<string>>(themes, target, selection, options?): { destroy: void; getTheme: void; refresh: void; setLocalThemes: void; setTransition: void; update: void }
Create a scoped-theme binding for an element: applies the scoped theme's CSS variables inline on the element and cleans them up on destroy.
See also: ScopedThemeBindingOptions
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | — |
target | HTMLElement | — |
selection | ScopedThemeSelection | — |
options | ScopedThemeBindingOptions (optional) | — |
Returns { destroy: void; getTheme: void; refresh: void; setLocalThemes: void; setTransition: void; update: void }
createSharedWorkerSync(): ThemeSelectionBroadcastAdapter | null
Create a theme-selection broadcast adapter backed by a SharedWorker.
The adapter relays theme selections between tabs/windows through a shared
worker, so every tab connected to the same worker receives the selection.
It requires SharedWorker support; when unavailable (or when the worker
cannot be created) it returns null (e.g. during SSR).
See also: destroySharedWorkerUrl
Returns ThemeSelectionBroadcastAdapter | null — A ThemeSelectionBroadcastAdapter, or null when SharedWorker
is unavailable.
const sync = createSharedWorkerSync();
sync?.post({ mode: "dark", family: "plum" });createStorageEventSync(key?, view?): ThemeSelectionBroadcastAdapter
Create a theme-selection sync adapter backed by localStorage and the
storage event.
The adapter writes the selection as JSON under a single key and notifies
subscribers of cross-tab changes through the storage event. It requires
a Window; when none is available it returns a no-op adapter (e.g. during
SSR).
See also: createThemeBroadcast, MultiWindowSyncOptions
| Parameter | Type | Description |
|---|---|---|
key | string (optional) | Storage key used for the selection. |
view | Window (optional) | The Window used to access storage and listen for storage events. Defaults to the global window when present. |
Returns ThemeSelectionBroadcastAdapter — A ThemeSelectionBroadcastAdapter.
const sync = createStorageEventSync();
sync.post({ mode: "dark", family: "plum" });createSyncFirstRoot<TRoot extends SyncFirstRenderRoot>(createRoot, flushSync, options?): CreateRootLike<TRoot>
Wraps a React createRoot so the first render call on each root it
creates is committed synchronously.
See also: themvoraVitePlugin
| Parameter | Type | Description |
|---|---|---|
createRoot | CreateRootLike<TRoot> | The real createRoot to delegate to. |
flushSync | __type(callback: __type(): void): void | React's flushSync. |
options | SyncFirstRootOptions (optional) | See SyncFirstRootOptions. |
Returns CreateRootLike<TRoot> — A createRoot that commits its first render synchronously.
React's concurrent root schedules the initial commit, so the browser can
paint a frame with the container still empty before React commits — one frame,
~33 ms, visible as the UI blinking on reload. flushSync around that first
render closes it, and it has to happen at the root: the offending frame is
painted before any of the application's React code runs, so no provider,
insertion effect or layout effect is in time.
Only the first render of each root is flushed. Every later render keeps
React's normal concurrent scheduling, so transitions, Suspense and
time-slicing behave exactly as before.
This is deliberately a plain function of its dependencies rather than something that reaches for React globals, so it can be unit-tested against stubs — the behaviour it encodes (first render flushed, later renders not) is otherwise only observable in a real browser.
createSystemThemeBinding<T extends ThemeDefinition<string>>(store, options): { destroy: void } | null
Create a binding that applies the theme for "system" mode, following
prefers-color-scheme live.
See also: SystemThemeBindingOptions
| Parameter | Type | Description |
|---|---|---|
store | ThemeStore<T> | — |
options | SystemThemeBindingOptions<T> | — |
Returns { destroy: void } | null
createThemeBootstrapScript<T extends ThemeDefinition<string>>(options): string
Generate an inline, blocking script that applies the persisted theme before first paint, preventing a flash of the wrong (or missing) theme on reload.
The script reads the saved selection from localStorage, resolves the theme
for the effective mode ("system" is resolved against prefers-color-scheme),
and writes the CSS variables plus DOM effects onto document.documentElement.
See also: buildThemeCssMap, createPrePaintScrollbarScript
| Parameter | Type | Description |
|---|---|---|
options | ThemeBootstrapScriptOptions<T> | — |
Returns string
createThemeBroadcast(options?): ThemeBroadcastAdapter | null
Create a theme-mode broadcast adapter backed by BroadcastChannel.
The adapter publishes the mode to a channel and notifies subscribers of
modes broadcast by other tabs/windows. It requires BroadcastChannel
support (or a custom channel); when neither is available it returns
null (e.g. during SSR).
See also: createStorageEventSync, ThemeSelectionBroadcastAdapter
| Parameter | Type | Description |
|---|---|---|
options | ThemeBroadcastOptions (optional) | The broadcast configuration. |
Returns ThemeBroadcastAdapter | null — A ThemeBroadcastAdapter, or null when no channel is available.
const broadcast = createThemeBroadcast({ channelName: "my-theme-mode" });
broadcast?.post("dark");createThemeDebugger<T extends ThemeDefinition<string>>(store, options?): ThemeDebugger<T>
Create a debugger that records theme changes on a theme store.
The debugger subscribes to the store and records an event whenever the
current theme changes. Call ThemeDebugger.record before a change to
attribute it to a specific source and label; otherwise the change is
attributed to "user". History is capped at maxEvents entries.
See also: ThemeDebugger
| Parameter | Type | Description |
|---|---|---|
store | ThemeStore<T> | The theme store to observe. |
options | { maxEvents?: number } (optional) | Optional configuration. |
Returns ThemeDebugger<T> — A ThemeDebugger bound to the store.
const debugger = createThemeDebugger(store, { maxEvents: 100 });
debugger.record("user", "switched to dark");createThemeDiff(prev, next, prefix?): ThemeDiff
Theme Diff Engine.
Compares the previously applied CSS variables against the incoming theme's variables per token group. Comparing the final resolved values (rather than raw theme definitions) means two themes that resolve to identical colors produce no diff — and nothing animates.
| Parameter | Type | Description |
|---|---|---|
prev | Map<string, string> | null | undefined | — |
next | Record<string, string> | — |
prefix | string (optional) | — |
Returns ThemeDiff
createThemeHistory<T extends ThemeDefinition<string>>(store, options?): ThemeHistory<T>
Creates an undo/redo history controller for a theme store.
See also: ThemeHistory, ThemeStore
| Parameter | Type | Description |
|---|---|---|
store | ThemeStore<T> | The store to track. |
options | ThemeHistoryOptions (optional) | History configuration (see ThemeHistoryOptions). |
Returns ThemeHistory<T> — A new theme history controller.
const history = createThemeHistory(store, { maxSteps: 20 });
history.undo();createThemeLifecycle<T extends ThemeDefinition<string>>(): ThemeLifecycle<T>
Creates a typed lifecycle event emitter for runtime events.
See also: ThemeLifecycle, ThemeLifecycleEventMap
Returns ThemeLifecycle<T> — A new lifecycle controller.
const lifecycle = createThemeLifecycle();
const off = lifecycle.on("afterThemeChange", ({ theme }) => log(theme));
lifecycle.emit("afterThemeChange", { theme });
off();createThemeModeController<T extends ThemeDefinition<string>>(options): { setMode: __type(nextMode: ThemeMode): void; destroy: void; getMode: void }
Create a theme-mode controller that resolves a mode into a concrete theme and keeps it applied to the store.
In system mode it follows the OS color-scheme preference live via a
system binding; in light/dark mode it applies the corresponding theme
directly. setMode refuses a value that is not "light", "dark" or
"system": the call is ignored — nothing is applied, persisted or
broadcast — and a TV_MODE_INVALID diagnostic is emitted, so getMode()
never reports a mode the runtime cannot render. Mode changes are persisted
and broadcast when the corresponding adapters are provided. The returned
controller is safe to destroy: after destroy() its methods become no-ops
and all subscriptions are released.
A persistence or broadcast adapter that throws does not abort the change: the
resolved theme is still applied and the failure is reported as a
TV_SYNC_FAILED diagnostic, so getMode() never reports a mode the screen
is not showing.
See also: ThemeSelectionState, createThemePersistence
| Parameter | Type | Description |
|---|---|---|
options | ThemeModeControllerOptions<T> | The controller configuration. |
Returns { setMode: __type(nextMode: ThemeMode): void; destroy: void; getMode: void } — A controller exposing getMode, setMode and destroy.
const controller = createThemeModeController({
store,
lightTheme,
darkTheme,
persistence: createThemePersistence(),
});
controller.setMode("dark");createThemePersistence(options?): ThemePersistenceAdapter | null
Create a theme-mode persistence adapter backed by Storage.
The adapter reads/writes the mode under a single key and notifies
subscribers of cross-tab changes through the storage event. It requires
a Window; when none is available it returns null (e.g. during SSR).
See also: createDefaultPersistence, ThemeSelectionPersistenceAdapter
| Parameter | Type | Description |
|---|---|---|
options | ThemePersistenceOptions (optional) | The persistence configuration. |
Returns ThemePersistenceAdapter | null — A ThemePersistenceAdapter, or null when no Window is
available.
const persistence = createThemePersistence({ key: "my-theme-mode" });
persistence?.set("dark");createThemeReadoutScript(): string
Builds the inline script that fills in bootstrap readouts and reconciles selection controls: the parts of the page that display or reflect a theme-derived value the server cannot know.
See also: createThemeBootstrapScript, readBootstrapState
Returns string — The script body to emit at the end of <body>, after the
elements it patches exist.
Three kinds of element opt in, and all three are reconciled from the same three values — the resolved theme, the mode selection and the family selection — because a control that lags the canvas by one value is the same bug in a smaller window:
| Attribute | Written | Meaning |
|---|---|---|
data-tv-readout | textContent | "theme", "label", "mode", "family", or "var:<custom-property>" |
data-tv-pressed + data-tv-value | aria-pressed | this element represents that option of "mode" / "family" |
data-tv-select | value | this <select> edits "mode" / "family" |
Why this exists: a server-rendered readout or control can only show the
server's resolution, and for "system" mode — or for any prerendered page,
which has no request to read a cookie from — that is a fallback the browser
overrides before the first paint. The canvas is corrected by the bootstrap,
but the text and the pressed state are not, so they settle once after
hydration, which is the last visible difference on an otherwise static page.
On a page that reloads repeatedly it reads as the label "fluctuating" between
the two themes.
data-tv-pressed writes aria-pressed and nothing else. That is the whole
point: the accessible state is the visual state, so a token class keyed off
aria-pressed needs no second attribute to keep in step, and a screen reader
can never announce a pressed option the page does not show as pressed.
Patching before the first paint closes that, but only if the framework then
leaves the element alone. In React that means pairing a readout with
suppressHydrationWarning on the same element: React renders its own value
during hydration, sees the DOM already differs, and — with the attribute —
neither warns nor rewrites. The framework's own post-hydration render then
produces the live value, which is the same value the script wrote, so nothing
moves. Without the suppression React would rewrite the text back to the
server's fallback and re-introduce the settle.
It is deliberately placed at the end of the body: the blocking script runs in
<head>, before these elements have been parsed, so it cannot patch them.
It reads the live document, not the page's build-time state. The values
come from <html>'s own data-theme / data-theme-selection-* attributes,
which by this point describe what the visitor is actually looking at, and
only fall back to the published bootstrap payload when those attributes are
absent. That is what makes the script idempotent, and idempotence is
load-bearing rather than tidy: <ClientRouter /> re-executes inline body
scripts on a client-side navigation, so this runs again on every navigation —
after the incoming page's readouts have already been brought up to date. A
script that wrote the initial selection would undo that, and every readout
would revert to the page-build default until the next theme change. Measured
on the example app: with the payload as the source, navigating from / with
cocoa-dark selected left the readouts at mint-light / system / mint
while the document was painted cocoa-dark.
createThemeRegistry<T extends ThemeDefinition<string>>(options?): ThemeRegistry<T>
Creates a theme registry.
See also: ThemeRegistry, resolveThemeRegistry
| Parameter | Type | Description |
|---|---|---|
options | ThemeRegistryOptions<T> (optional) | Initial themes and registry configuration. |
Returns ThemeRegistry<T> — A new ThemeRegistry.
const registry = createThemeRegistry({ themes: [lightTheme, darkTheme] });
registry.get("light");createThemeRuntime<T extends ThemeDefinition<string>>(options?): ThemeRuntime<T>
Creates an independent Themvora runtime — the single entry point for theming.
The runtime wires together the theme store, selection controller (mode/family/system binding), persistence, broadcast (cross-tab sync), history, scheduling, the DOM + CSS-variable bindings, and the adapter registry.
See also: ThemeRuntime, createThemeStore
| Parameter | Type | Description |
|---|---|---|
options | ThemeRuntimeOptions<T> (optional) | Runtime configuration and initial theme definitions. |
Returns ThemeRuntime<T> — A new ThemeRuntime instance.
The returned runtime must be destroyed when its owning application lifecycle ends.
const runtime = createThemeRuntime({
themes: [lightTheme, darkTheme],
defaultTheme: "light",
initialMode: "system",
});
runtime.selection.setMode("dark");createThemeSchedule<T extends ThemeDefinition<string>>(store, themes, options): ThemeSchedule
Framework-neutral sunrise/sunset scheduling controller. Wraps the core
createScheduledThemeBinding engine with an explicit on/off switch and a
reactive state snapshot (sunrise, sunset, nextTransition, ...) so
frameworks can expose it through their native accessors.
lightTheme and darkTheme are optional: when omitted the schedule
derives them from the currently selected theme's family (e.g. current
plum-dark → scheduled plum-light/plum-dark) and falls back to the
built-in neutral light/dark themes, re-resolving whenever the user
switches theme family.
The engine itself lives entirely in core — every framework wrapper talks to this single contract.
| Parameter | Type | Description |
|---|---|---|
store | ThemeScheduleStore<T> | — |
themes | readonly T[] | — |
options | ThemeScheduleOptions<T> | — |
Returns ThemeSchedule
createThemeScrollbar(store, options?): OverlayScrollbarHandle | null
Alias landing in the public API.
| Parameter | Type | Description |
|---|---|---|
store | ThemeStore | — |
options | OverlayScrollbarOptions (optional) | — |
Returns OverlayScrollbarHandle | null
createThemeSelectionBroadcast(options?): ThemeSelectionBroadcastAdapter | null
Create a broadcast adapter that publishes selection changes to other tabs/windows and applies incoming changes.
| Parameter | Type | Description |
|---|---|---|
options | ThemeSelectionBroadcastOptions (optional) | — |
Returns ThemeSelectionBroadcastAdapter | null
createThemeStore<T extends ThemeDefinition<string>>(options): ThemeStore<T>
Creates a theme store: a framework-free container for the active theme.
The store holds the current theme and notifies subscribers when it
changes. Use the higher-level createThemeRuntime for the full runtime;
use the store directly when you only need a reactive current-theme
container.
See also: ThemeStore, createThemeRuntime
| Parameter | Type | Description |
|---|---|---|
options | ThemeStoreOptions<T> | Store configuration, including the initial theme. |
Returns ThemeStore<T> — A new theme store.
const store = createThemeStore({ initialTheme: lightTheme });
store.subscribe((theme) => console.log(theme.name));
store.set(darkTheme);createTransitionPlan(diff, options?, env?): TransitionPlan | null
Transition Planner.
Turns a ThemeDiff into a concrete TransitionPlan:
- colors animate through the registered theme custom properties on
:root, - every other changed group contributes the concrete CSS properties it maps to (radius → border-radius, spacing → padding/margin/gap, …).
Returns null when there is nothing animatable: transitions disabled,
reduced motion, an "instant" preset, or a diff where only non-animatable
groups (layout/z-index/breakpoints) changed.
| Parameter | Type | Description |
|---|---|---|
diff | ThemeDiff | — |
options | ThemeTransitionOptions (optional) | — |
env | { reducedMotion?: boolean } (optional) | — |
Returns TransitionPlan | null
createVueThemeBootstrapScript<T extends ThemeDefinition<string>>(options): string
Build the blocking zero-flash <head> script for a Vue app (SSR or SPA).
Inlines core's createThemeBootstrapScript with the Vue defaults
(storageKey: "theme-selection", prefix: "theme-" — the same values the
Vue ThemeProvider persistence and CSS variables use), so the persisted
theme is applied before first paint. Emit the returned string as a
blocking <script> inside <head>.
See also: buildThemeCssMap
| Parameter | Type | Description |
|---|---|---|
options | ThemeBootstrapScriptOptions<T> | — |
Returns string
darkModeCSSTemplate(variables): string
Generate a @media (prefers-color-scheme: dark) CSS block carrying the given
variables.
See also: systemModeCSSTemplate
| Parameter | Type | Description |
|---|---|---|
variables | Record<string, string> | The CSS variables to emit under the dark media query. |
Returns string — A @media (prefers-color-scheme: dark) block targeting :root,
escaped so it cannot terminate a <style> element (</ becomes </,
which CSS parses identically).
This is a pre-script fallback only, and it cannot beat an inline style
on the same element: inline declarations outrank every stylesheet rule
regardless of specificity. So it is only safe when nothing inlines the light
variables — do not pair it with a server render that writes them onto
<html>, or an OS-dark visitor keeps the light ones and this block is inert.
When the resolved mode is "system", use systemModeCSSTemplate
instead: it emits both schemes and expects no inline variables.
defineTheme<Name extends string, T extends ThemeDefinition<Name>>(theme): T
Define a theme. Currently returns the definition unchanged; it exists to give themes a consistent shape and future validation.
See also: extendTheme, composeTheme
| Parameter | Type | Description |
|---|---|---|
theme | T | — |
Returns T
defineThemvoraConfig<T extends ThemeDefinition<string>>(config): ThemvoraConfig<T>
Declares the application's Themvora configuration.
See also: ThemvoraConfig
| Parameter | Type | Description |
|---|---|---|
config | ThemvoraConfig<T> | The configuration. |
Returns ThemvoraConfig<T> — The same object, typed.
An identity function. Its job is to give the configuration a name, a type and a validation point, so the Vite plugin can discover it by convention and the provider can consume the same object rather than a copy of it.
// At the project root
import { defineTheme, defineThemvoraConfig } from "@themvora/core";
const themes = [
defineTheme({
name: "brand-light",
meta: { family: "brand", mode: "light" },
tokens: { colors: { background: "#ffffff" } },
}),
defineTheme({
name: "brand-dark",
meta: { family: "brand", mode: "dark" },
tokens: { colors: { background: "#101014" } },
}),
];
export default defineThemvoraConfig({
themes,
defaultTheme: "brand-light",
initialMode: "system",
});describeRoleUsage(role): { advisory: { description: string; owner: ContextOwner }[]; restricted: string[]; supported: string[] }
What a role is for — the "safe usage" description.
The docs and Theme Studio show this instead of a bare hex, because how a token may be used is the thing a reader actually needs. A ratio answers "is it readable here"; this answers "is it readable here on purpose".
| Parameter | Type | Description |
|---|---|---|
role | CoreColor | The role to describe. |
Returns { advisory: { description: string; owner: ContextOwner }[]; restricted: string[]; supported: string[] } — Where the role is supported, and where it is not.
destroySharedWorkerUrl(): void
Release the shared worker's blob URL.
Revokes the object URL created for the shared worker script and resets the cached URL, so a subsequent createSharedWorkerSync call creates a fresh worker. Safe to call multiple times; it is a no-op when no URL is cached.
Returns void
diffThemes(a, b, options?): ThemeDiffReport
Diff two themes, or two light/dark theme sets.
Accepts a single theme or a { light, dark } pair on either side. Resolves
inheritance through options.themes when a definition declares extends, and
resolves a mode: "system" selector through the same registry.
Only light and dark are visual modes. "system" is a selector over that
pair, resolved before any comparison, and never appears in the report.
hasChanges reflects token changes only. Provenance differences are
reported separately, because two themes with identical tokens but different
seeds render identically.
| Parameter | Type | Description |
|---|---|---|
a | ThemeDefinition<string> | ThemeSet | The first theme, or light/dark set. |
b | ThemeDefinition<string> | ThemeSet | The second theme, or light/dark set. |
options | ThemeDiffOptions (optional) | Registry, prefersDark, includeUnchanged, and mode filter. |
Returns ThemeDiffReport — The diff report.
const report = diffThemes(mintLight, irisLight);
report.modes.light?.changes.forEach((c) => {
console.log(c.path, c.before, "→", c.after);
});disposeThemeTransitionStyles(target): void
Release every transition style the coordinator owns for target: cancels an
in-flight run and detaches the persistent :root transition stylesheet and
the descendant-suppression stylesheet.
cancelThemeAnimation deliberately leaves the :root { transition }
rule in place between runs — it is written once and reused, so every
subsequent change keeps animating. That rule must go when the feature is
turned off or the owner is disposed, otherwise later variable swaps still
interpolate through it: a theme switch after transition: false would
animate despite the plan being null. Scoped targets never install the
:root rule (it is document-wide), so for them this only clears the
suppression node and the animating flag.
| Parameter | Type | Description |
|---|---|---|
target | HTMLElement | — |
Returns void
emitDiagnostic(diagnostic, options?): void
Emit a diagnostic to the console.
Developer-facing Themvora diagnostics go through here rather than calling
console directly, so that the level, the code, the deduplication and the
development/production formatting stay consistent across packages.
Repeated identical diagnostics are suppressed by default; see EmitDiagnosticOptions.dedupe. Use resetDiagnosticEmission to clear that memory.
See also: createDiagnostic, formatDiagnostic
| Parameter | Type | Description |
|---|---|---|
diagnostic | ThemeDiagnostic | The diagnostic to emit. |
options | EmitDiagnosticOptions (optional) | Environment, deduplication and sink overrides. |
Returns void
emitInvalidOptionDiagnostic(option): void
Report an unusable transition/scheduling option supplied to configure().
level: "warning" — the runtime keeps the previous setting for the affected
subsystem (a defined state) rather than corrupting a healthy runtime or
throwing. Deduplicated by emitDiagnostic, so an adapter that forwards
the same invalid value on every render logs it once.
| Parameter | Type | Description |
|---|---|---|
option | InvalidOption | — |
Returns void
emitNeutralFallbackDiagnostic(): void
Report that no usable theme was available and the neutral fallback was used.
level: "warning" — the runtime recovers safely, so this is reported, not
thrown. Deduplicated like every other diagnostic.
Returns void
emitScheduledThemeUnresolvedDiagnostic(names): void
Report that a scheduled configuration named light/dark themes that are not
registered, so the schedule cannot drive the selection.
level: "warning" — the schedule is installed but reports no light/dark pair,
matching the existing TV_SCHEDULE_THEME_UNRESOLVED contract used by the
scheduled plugin. Deduplicated by emitDiagnostic.
| Parameter | Type | Description |
|---|---|---|
names | { darkTheme?: string; lightTheme?: string } | — |
Returns void
emitUnknownFamilyDiagnostic(requested, resolved, themes): void
Report a family that is not registered in the effective catalog.
level: "error" because an explicitly requested family that cannot resolve is
a configuration mistake, not a supported absence. Deduplication is handled by
emitDiagnostic: the same invalid value reports once, a new invalid
value reports again.
| Parameter | Type | Description |
|---|---|---|
requested | string | — |
resolved | string | — |
themes | readonly ThemeDefinition<string>[] | — |
Returns void
evaluateExpression(expr): string
Evaluate a numeric arithmetic expression and return the result as a string.
Supports +, -, *, /, parentheses, and an optional trailing CSS unit
(e.g. "1.5 * 2rem" → "3rem"). Integer results are returned without a
decimal point; non-integer results are rounded to two decimals. When the
input is not a valid expression, or evaluation fails, the original string is
returned unchanged.
See also: isExpression
| Parameter | Type | Description |
|---|---|---|
expr | string | The expression string to evaluate. |
Returns string — The evaluated result string, or expr unchanged when it cannot be
evaluated.
extendTheme<TName extends string, TBase extends ThemeDefinition<string>>(name, base, overrides?): ThemeDefinition<TName>
Create a new theme by extending a base theme with overrides, merging token groups recursively.
See also: defineTheme, mergeTokens
| Parameter | Type | Description |
|---|---|---|
name | TName | — |
base | TBase | — |
overrides | TokenOverrides & { meta?: Partial<ThemeMeta> } (optional) | — |
Returns ThemeDefinition<TName>
findGeneratedTheme<T extends ThemeDefinition<string>>(themes, active?): GeneratedThemeLookup<T>
Locate the generated theme among a provider's registered themes.
Deterministic and non-throwing:
- No generated theme registered →
"missing". - Exactly one →
"found". - More than one →
"found"for the one whose name matchesactive(the current active selection); otherwise"ambiguous". The first candidate is never returned on a tie.
See also: resolveGeneratedTheme
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | The themes registered with the provider, in registration order. |
active | T (optional) | The currently active theme, used to disambiguate multiple generated themes. Omitted on a surface with no active selection. |
Returns GeneratedThemeLookup<T> — The lookup result.
flattenTokens(tokens): Record<string, string>
Flatten a theme's token groups into a single dot-path → value map.
Nested token objects are flattened with dot-separated paths (e.g.
colors.primary, typography.fontSizes.base). Only string values are
included; non-string values are skipped. The result is the lookup surface
used to resolve token references.
See also: resolveTokens
| Parameter | Type | Description |
|---|---|---|
tokens | ThemeTokens | The theme token groups to flatten. |
Returns Record<string, string> — A flat map of dot-path keys to string token values.
formatDiagnostic(diagnostic, options?): string
Render a diagnostic as a single log line.
This is the environment-specific half of the model: the diagnostic itself is plain data, and this decides how much of it a given environment should see. In development the context, hint and docs link are appended, because that is where they are actionable. Outside development the message is emitted alone — the failure is never hidden, but the surrounding detail is not shipped to end users.
See also: emitDiagnostic
| Parameter | Type | Description |
|---|---|---|
diagnostic | ThemeDiagnostic | The diagnostic to render. |
options | { dev?: boolean } (optional) | dev overrides environment detection. Intended for tests and for callers that already know which build they are in. |
Returns string — A single-line, prefixed string.
generateTheme(options): GeneratedThemePair
Generate a cohesive light/dark theme pair from a single seed color.
Light and dark are generated independently from the same identity — the
dark theme is not an inversion of the light one — so the brand hue survives
the mode change. Every semantic pair is solved to the contrast contract with a
safety margin before the theme is returned, and the seed is recorded in
meta.generation as provenance.
See also: validateTheme, defineTheme
| Parameter | Type | Description |
|---|---|---|
options | GenerateThemeOptions | The seed color and generation options. |
Returns GeneratedThemePair — A { light, dark } pair of theme definitions sharing one family.
const { light, dark } = generateTheme({ seed: "#d97706", family: "brand" });getAccessibilityProfiles(): { meta: { label: "High Contrast Light" | "High Contrast Dark"; mode: "light" | "dark"; order: 30 | 40; tags: ["accessibility", "high-contrast"] }; name: "high-contrast-light" | "high-contrast-dark"; tokens: { colors: { accent: "#0000ee" | "#4488ff"; accentForeground: "#000000" | "#ffffff"; background: "#000000" | "#ffffff"; border: "#000000"; card: "#000000" | "#ffffff"; cardForeground: "#000000" | "#ffffff"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#ffffff"; input: "#000000"; muted: "#e0e0e0" | "#333333"; mutedForeground: "#111111" | "#eeeeee"; popover: "#000000" | "#ffffff"; popoverForeground: "#000000" | "#ffffff"; primary: "#0000ee" | "#4488ff"; primaryForeground: "#000000" | "#ffffff"; ring: "#0000ee" | "#4488ff"; secondary: "#e0e0e0" | "#333333"; secondaryForeground: "#000000" | "#ffffff"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "4px" } } } | { meta: { label: "Large Text Light" | "Large Text Dark"; mode: "light" | "dark"; order: 35 | 45; tags: ["accessibility", "large-text"] }; name: "large-text-light" | "large-text-dark"; tokens: { colors: { accent: "#4488ff" | "#0055cc"; accentForeground: "#ffffff"; background: "#fafafa" | "#0a0a0a"; border: "#cccccc" | "#444444"; card: "#ffffff" | "#111111"; cardForeground: "#000000" | "#f0f0f0"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#f0f0f0"; input: "#cccccc" | "#444444"; muted: "#e8e8e8" | "#2a2a2a"; mutedForeground: "#333333" | "#cccccc"; popover: "#ffffff" | "#111111"; popoverForeground: "#000000" | "#f0f0f0"; primary: "#4488ff" | "#0055cc"; primaryForeground: "#ffffff"; ring: "#4488ff" | "#0055cc"; secondary: "#e8e8e8" | "#2a2a2a"; secondaryForeground: "#000000" | "#f0f0f0"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "8px" }; typography: { fontFamilies: { mono: "monospace"; sans: "system-ui, sans-serif" }; fontSizes: { 2xl: "2.25rem"; 3xl: "3rem"; 4xl: "3.75rem"; 5xl: "4.5rem"; 6xl: "6rem"; base: "1.25rem"; lg: "1.5rem"; sm: "1.125rem"; xl: "1.875rem"; xs: "1rem" }; lineHeights: { normal: "1.8"; relaxed: "2.0"; tight: "1.4" } } } }[]
Build the accessibility profile theme set: high-contrast and large-text themes for both light and dark modes.
Returns { meta: { label: "High Contrast Light" | "High Contrast Dark"; mode: "light" | "dark"; order: 30 | 40; tags: ["accessibility", "high-contrast"] }; name: "high-contrast-light" | "high-contrast-dark"; tokens: { colors: { accent: "#0000ee" | "#4488ff"; accentForeground: "#000000" | "#ffffff"; background: "#000000" | "#ffffff"; border: "#000000"; card: "#000000" | "#ffffff"; cardForeground: "#000000" | "#ffffff"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#ffffff"; input: "#000000"; muted: "#e0e0e0" | "#333333"; mutedForeground: "#111111" | "#eeeeee"; popover: "#000000" | "#ffffff"; popoverForeground: "#000000" | "#ffffff"; primary: "#0000ee" | "#4488ff"; primaryForeground: "#000000" | "#ffffff"; ring: "#0000ee" | "#4488ff"; secondary: "#e0e0e0" | "#333333"; secondaryForeground: "#000000" | "#ffffff"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "4px" } } } | { meta: { label: "Large Text Light" | "Large Text Dark"; mode: "light" | "dark"; order: 35 | 45; tags: ["accessibility", "large-text"] }; name: "large-text-light" | "large-text-dark"; tokens: { colors: { accent: "#4488ff" | "#0055cc"; accentForeground: "#ffffff"; background: "#fafafa" | "#0a0a0a"; border: "#cccccc" | "#444444"; card: "#ffffff" | "#111111"; cardForeground: "#000000" | "#f0f0f0"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#f0f0f0"; input: "#cccccc" | "#444444"; muted: "#e8e8e8" | "#2a2a2a"; mutedForeground: "#333333" | "#cccccc"; popover: "#ffffff" | "#111111"; popoverForeground: "#000000" | "#f0f0f0"; primary: "#4488ff" | "#0055cc"; primaryForeground: "#ffffff"; ring: "#4488ff" | "#0055cc"; secondary: "#e8e8e8" | "#2a2a2a"; secondaryForeground: "#000000" | "#f0f0f0"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "8px" }; typography: { fontFamilies: { mono: "monospace"; sans: "system-ui, sans-serif" }; fontSizes: { 2xl: "2.25rem"; 3xl: "3rem"; 4xl: "3.75rem"; 5xl: "4.5rem"; 6xl: "6rem"; base: "1.25rem"; lg: "1.5rem"; sm: "1.125rem"; xl: "1.875rem"; xs: "1rem" }; lineHeights: { normal: "1.8"; relaxed: "2.0"; tight: "1.4" } } } }[] — An array of four accessibility theme definitions.
getBrandPresets(): ThemeDefinition<string>[]
Build the brand preset theme set: a light and dark theme for each brand (Apple, GitHub, Vercel, Slack, Discord).
Returns ThemeDefinition<string>[] — An array of brand theme definitions, one light and one dark per
brand.
getBrowserTimeZone(): string | null
Detect the visitor's IANA timezone, e.g. "Asia/Kathmandu". Returns null
when Intl is unavailable or reports an empty zone.
Returns string | null
getBuiltInThemes(): ThemeDefinition<string> | { meta: { label: "High Contrast Light" | "High Contrast Dark"; mode: "light" | "dark"; order: 30 | 40; tags: ["accessibility", "high-contrast"] }; name: "high-contrast-light" | "high-contrast-dark"; tokens: { colors: { accent: "#0000ee" | "#4488ff"; accentForeground: "#000000" | "#ffffff"; background: "#000000" | "#ffffff"; border: "#000000"; card: "#000000" | "#ffffff"; cardForeground: "#000000" | "#ffffff"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#ffffff"; input: "#000000"; muted: "#e0e0e0" | "#333333"; mutedForeground: "#111111" | "#eeeeee"; popover: "#000000" | "#ffffff"; popoverForeground: "#000000" | "#ffffff"; primary: "#0000ee" | "#4488ff"; primaryForeground: "#000000" | "#ffffff"; ring: "#0000ee" | "#4488ff"; secondary: "#e0e0e0" | "#333333"; secondaryForeground: "#000000" | "#ffffff"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "4px" } } } | { meta: { label: "Large Text Light" | "Large Text Dark"; mode: "light" | "dark"; order: 35 | 45; tags: ["accessibility", "large-text"] }; name: "large-text-light" | "large-text-dark"; tokens: { colors: { accent: "#4488ff" | "#0055cc"; accentForeground: "#ffffff"; background: "#fafafa" | "#0a0a0a"; border: "#cccccc" | "#444444"; card: "#ffffff" | "#111111"; cardForeground: "#000000" | "#f0f0f0"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#f0f0f0"; input: "#cccccc" | "#444444"; muted: "#e8e8e8" | "#2a2a2a"; mutedForeground: "#333333" | "#cccccc"; popover: "#ffffff" | "#111111"; popoverForeground: "#000000" | "#f0f0f0"; primary: "#4488ff" | "#0055cc"; primaryForeground: "#ffffff"; ring: "#4488ff" | "#0055cc"; secondary: "#e8e8e8" | "#2a2a2a"; secondaryForeground: "#000000" | "#f0f0f0"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "8px" }; typography: { fontFamilies: { mono: "monospace"; sans: "system-ui, sans-serif" }; fontSizes: { 2xl: "2.25rem"; 3xl: "3rem"; 4xl: "3.75rem"; 5xl: "4.5rem"; 6xl: "6rem"; base: "1.25rem"; lg: "1.5rem"; sm: "1.125rem"; xl: "1.875rem"; xs: "1rem" }; lineHeights: { normal: "1.8"; relaxed: "2.0"; tight: "1.4" } } } }[]
Build the complete set of built-in themes shipped with Themvora.
Combines the neutral themes, preset themes, brand presets, and accessibility profiles into a single array ready to be registered with a theme runtime.
Every theme passes through ensureReadableContrast on the way out, so a semantic foreground that would fail AA is corrected before any consumer sees it.
Returns ThemeDefinition<string> | { meta: { label: "High Contrast Light" | "High Contrast Dark"; mode: "light" | "dark"; order: 30 | 40; tags: ["accessibility", "high-contrast"] }; name: "high-contrast-light" | "high-contrast-dark"; tokens: { colors: { accent: "#0000ee" | "#4488ff"; accentForeground: "#000000" | "#ffffff"; background: "#000000" | "#ffffff"; border: "#000000"; card: "#000000" | "#ffffff"; cardForeground: "#000000" | "#ffffff"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#ffffff"; input: "#000000"; muted: "#e0e0e0" | "#333333"; mutedForeground: "#111111" | "#eeeeee"; popover: "#000000" | "#ffffff"; popoverForeground: "#000000" | "#ffffff"; primary: "#0000ee" | "#4488ff"; primaryForeground: "#000000" | "#ffffff"; ring: "#0000ee" | "#4488ff"; secondary: "#e0e0e0" | "#333333"; secondaryForeground: "#000000" | "#ffffff"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "4px" } } } | { meta: { label: "Large Text Light" | "Large Text Dark"; mode: "light" | "dark"; order: 35 | 45; tags: ["accessibility", "large-text"] }; name: "large-text-light" | "large-text-dark"; tokens: { colors: { accent: "#4488ff" | "#0055cc"; accentForeground: "#ffffff"; background: "#fafafa" | "#0a0a0a"; border: "#cccccc" | "#444444"; card: "#ffffff" | "#111111"; cardForeground: "#000000" | "#f0f0f0"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#f0f0f0"; input: "#cccccc" | "#444444"; muted: "#e8e8e8" | "#2a2a2a"; mutedForeground: "#333333" | "#cccccc"; popover: "#ffffff" | "#111111"; popoverForeground: "#000000" | "#f0f0f0"; primary: "#4488ff" | "#0055cc"; primaryForeground: "#ffffff"; ring: "#4488ff" | "#0055cc"; secondary: "#e8e8e8" | "#2a2a2a"; secondaryForeground: "#000000" | "#f0f0f0"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "8px" }; typography: { fontFamilies: { mono: "monospace"; sans: "system-ui, sans-serif" }; fontSizes: { 2xl: "2.25rem"; 3xl: "3rem"; 4xl: "3.75rem"; 5xl: "4.5rem"; 6xl: "6rem"; base: "1.25rem"; lg: "1.5rem"; sm: "1.125rem"; xl: "1.875rem"; xs: "1rem" }; lineHeights: { normal: "1.8"; relaxed: "2.0"; tight: "1.4" } } } }[] — An array of all built-in theme definitions.
getContrastRatio(foreground, background): number
Compute the WCAG contrast ratio between two colors.
The ratio is (L1 + 0.05) / (L2 + 0.05) where L1/L2 are the relative
luminances of the lighter and darker colors, yielding a value in the range
1 (identical colors) to 21 (black on white). Colors are parsed as hex.
See also: validateThemeContrast
| Parameter | Type | Description |
|---|---|---|
foreground | string | The foreground color (hex). |
background | string | The background color (hex). |
Returns number — The contrast ratio, a number between 1 and 21.
getDefaultThemes(): ThemeDefinition<string>[]
Build the default theme family set: a light and dark theme for each of the original six built-in color families (oat, berry, mint, citrus, cocoa, plum).
Returns ThemeDefinition<string>[] — An array of ThemeDefinition objects, one light and one dark per
family, ready to be registered with a theme runtime.
getFallbackThemes<T extends ThemeDefinition<string>>(): readonly T[]
The canonical neutral fallback catalog.
A single source shared by every adapter: the framework packages never define their own fallback palette.
Returns readonly T[]
getHighContrastTheme(mode): { meta: { label: "High Contrast Light" | "High Contrast Dark"; mode: "light" | "dark"; order: 30 | 40; tags: ["accessibility", "high-contrast"] }; name: "high-contrast-light" | "high-contrast-dark"; tokens: { colors: { accent: "#0000ee" | "#4488ff"; accentForeground: "#000000" | "#ffffff"; background: "#000000" | "#ffffff"; border: "#000000"; card: "#000000" | "#ffffff"; cardForeground: "#000000" | "#ffffff"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#ffffff"; input: "#000000"; muted: "#e0e0e0" | "#333333"; mutedForeground: "#111111" | "#eeeeee"; popover: "#000000" | "#ffffff"; popoverForeground: "#000000" | "#ffffff"; primary: "#0000ee" | "#4488ff"; primaryForeground: "#000000" | "#ffffff"; ring: "#0000ee" | "#4488ff"; secondary: "#e0e0e0" | "#333333"; secondaryForeground: "#000000" | "#ffffff"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "4px" } } }
Build a high-contrast theme for the given mode.
Uses maximum-contrast colors (pure black/white surfaces, saturated primary) to maximize legibility for users with low vision.
| Parameter | Type | Description |
|---|---|---|
mode | "light" | "dark" | The color mode of the theme. |
Returns { meta: { label: "High Contrast Light" | "High Contrast Dark"; mode: "light" | "dark"; order: 30 | 40; tags: ["accessibility", "high-contrast"] }; name: "high-contrast-light" | "high-contrast-dark"; tokens: { colors: { accent: "#0000ee" | "#4488ff"; accentForeground: "#000000" | "#ffffff"; background: "#000000" | "#ffffff"; border: "#000000"; card: "#000000" | "#ffffff"; cardForeground: "#000000" | "#ffffff"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#ffffff"; input: "#000000"; muted: "#e0e0e0" | "#333333"; mutedForeground: "#111111" | "#eeeeee"; popover: "#000000" | "#ffffff"; popoverForeground: "#000000" | "#ffffff"; primary: "#0000ee" | "#4488ff"; primaryForeground: "#000000" | "#ffffff"; ring: "#0000ee" | "#4488ff"; secondary: "#e0e0e0" | "#333333"; secondaryForeground: "#000000" | "#ffffff"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "4px" } } } — A high-contrast theme definition tagged "accessibility" and
"high-contrast".
getLargeTextTheme(mode): { meta: { label: "Large Text Light" | "Large Text Dark"; mode: "light" | "dark"; order: 35 | 45; tags: ["accessibility", "large-text"] }; name: "large-text-light" | "large-text-dark"; tokens: { colors: { accent: "#4488ff" | "#0055cc"; accentForeground: "#ffffff"; background: "#fafafa" | "#0a0a0a"; border: "#cccccc" | "#444444"; card: "#ffffff" | "#111111"; cardForeground: "#000000" | "#f0f0f0"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#f0f0f0"; input: "#cccccc" | "#444444"; muted: "#e8e8e8" | "#2a2a2a"; mutedForeground: "#333333" | "#cccccc"; popover: "#ffffff" | "#111111"; popoverForeground: "#000000" | "#f0f0f0"; primary: "#4488ff" | "#0055cc"; primaryForeground: "#ffffff"; ring: "#4488ff" | "#0055cc"; secondary: "#e8e8e8" | "#2a2a2a"; secondaryForeground: "#000000" | "#f0f0f0"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "8px" }; typography: { fontFamilies: { mono: "monospace"; sans: "system-ui, sans-serif" }; fontSizes: { 2xl: "2.25rem"; 3xl: "3rem"; 4xl: "3.75rem"; 5xl: "4.5rem"; 6xl: "6rem"; base: "1.25rem"; lg: "1.5rem"; sm: "1.125rem"; xl: "1.875rem"; xs: "1rem" }; lineHeights: { normal: "1.8"; relaxed: "2.0"; tight: "1.4" } } } }
Build a large-text theme for the given mode.
Enlarges the typography scale and uses high-contrast colors so text remains readable for users who need larger type.
| Parameter | Type | Description |
|---|---|---|
mode | "light" | "dark" | The color mode of the theme. |
Returns { meta: { label: "Large Text Light" | "Large Text Dark"; mode: "light" | "dark"; order: 35 | 45; tags: ["accessibility", "large-text"] }; name: "large-text-light" | "large-text-dark"; tokens: { colors: { accent: "#4488ff" | "#0055cc"; accentForeground: "#ffffff"; background: "#fafafa" | "#0a0a0a"; border: "#cccccc" | "#444444"; card: "#ffffff" | "#111111"; cardForeground: "#000000" | "#f0f0f0"; destructive: "#cc0000" | "#dc2626"; destructiveForeground: "#ffffff"; foreground: "#000000" | "#f0f0f0"; input: "#cccccc" | "#444444"; muted: "#e8e8e8" | "#2a2a2a"; mutedForeground: "#333333" | "#cccccc"; popover: "#ffffff" | "#111111"; popoverForeground: "#000000" | "#f0f0f0"; primary: "#4488ff" | "#0055cc"; primaryForeground: "#ffffff"; ring: "#4488ff" | "#0055cc"; secondary: "#e8e8e8" | "#2a2a2a"; secondaryForeground: "#000000" | "#f0f0f0"; success: "#008000" | "#16a34a"; successForeground: "#ffffff" }; radius: { lg: "8px" }; typography: { fontFamilies: { mono: "monospace"; sans: "system-ui, sans-serif" }; fontSizes: { 2xl: "2.25rem"; 3xl: "3rem"; 4xl: "3.75rem"; 5xl: "4.5rem"; 6xl: "6rem"; base: "1.25rem"; lg: "1.5rem"; sm: "1.125rem"; xl: "1.875rem"; xs: "1rem" }; lineHeights: { normal: "1.8"; relaxed: "2.0"; tight: "1.4" } } } } — A large-text theme definition tagged "accessibility" and
"large-text".
getLocationForTimeZone(timeZone): TimeZoneLocation | null
Look up the reference coordinates for an IANA timezone. Returns null
when the zone is unknown (or Etc/GMT±n, which is derived from offset).
| Parameter | Type | Description |
|---|---|---|
timeZone | string | — |
Returns TimeZoneLocation | null
getNeutralThemes(): [ThemeDefinition<string>, ThemeDefinition<string>]
Build the neutral light and dark themes.
These are the framework's baseline themes: a full token set (colors, radius, spacing, shadows, border widths, z-index, breakpoints, typography, and code) with no color family applied. They are the fallback when no family is selected. Their colors are generated, so they satisfy the same contrast contract as every preset.
Returns [ThemeDefinition<string>, ThemeDefinition<string>] — A [light, dark] tuple of neutral theme definitions.
getPresetCatalog(kind?): PresetCatalogEntry[]
The preset catalog, derived from the recipes.
| Parameter | Type | Description |
|---|---|---|
kind | PresetKind (optional) | Restrict to "default" or "brand". Omit for both. |
Returns PresetCatalogEntry[] — The catalog entries, in recipe order.
getPresetThemes(overrides?): ThemeDefinition<string>[]
Build the curated preset theme set: a light and dark theme for each preset color family (oat, berry, mint, citrus, cocoa, plum, iris, sky, graphite).
Each preset is generated from a recipe — seed, style and radius — by the same
semantic-v2 pipeline generateTheme() uses, so every preset already satisfies
the contrast contract and the visual relationship checks before it is returned.
Optional per-family, per-mode token overrides are applied on top, afterwards.
| Parameter | Type | Description |
|---|---|---|
overrides | Partial<Record<PresetFamily, Partial<Record<PresetVariant, PresetVariantOverride>>>> (optional) | Optional per-family, per-mode token overrides. |
Returns ThemeDefinition<string>[] — An array of preset theme definitions, one light and one dark per
family.
const themes = getPresetThemes({
plum: { light: { tokens: { colors: { primary: "#6d28d9" } } } },
});getThemeFamily(theme): string
Get a theme's family. Themes without meta.family belong to the
"default" family.
See also: resolveThemeName
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | — |
Returns string
getThemeMode(theme): ThemeMode
Get the color mode of a theme. Uses meta.mode when present; otherwise
infers it from the theme name (e.g. "mint-dark" → "dark"). This keeps
simple theme definitions working:
[{ name: "light", ... }, { name: "dark", ... }] resolve and toggle
correctly without requiring meta.mode.
See also: resolveThemeName
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | — |
Returns ThemeMode
getTimeZoneList(): string[]
All known timezone ids, sorted alphabetically. Useful for building pickers (the docs site uses it for its timezone selector).
Returns string[]
hasForegroundPreference(role): boolean
Whether a foreground role's choice is governed by a declared preference.
| Parameter | Type | Description |
|---|---|---|
role | CoreColor | The foreground role. |
Returns boolean — true when the role has a declared preference.
hideNativeScrollbar(): __type(): void
Hide the native scrollbar and register a claim that keeps it hidden.
Returns the release function for that claim. The hiding is applied
idempotently (the class may already be server-rendered, the stylesheet may
already exist), and it is released when the last claim goes away — so
createOverlayScrollbar and its destroy() are a matched pair rather than
a one-way switch.
Returns __type(): void
isCoreColor(key): key is CoreColor
Whether a colour key is part of the core contract.
| Parameter | Type | Description |
|---|---|---|
key | string | The colour key to test. |
Returns key is CoreColor
isExpression(value): boolean
Determine whether a string is a numeric arithmetic expression.
An expression is a string containing +, -, *, or / over numbers and
parentheses, optionally ending in a CSS unit (e.g. "1.5 * 2rem"). Function
calls such as contrast(...) and auto() are not treated as expressions.
| Parameter | Type | Description |
|---|---|---|
value | string | The string to test. |
Returns boolean — true when value is a numeric arithmetic expression.
isGeneratedTheme(theme): boolean
Whether a theme was produced by the public generateTheme call.
Matches on the explicit origin marker only. It deliberately does not infer from a theme's name, family, or colors: the built-in presets and the neutral baseline are produced by the same engine and would otherwise be mistaken for application-generated themes, and a hand-authored theme could impersonate one by adopting a familiar id.
See also: resolveGeneratedTheme
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme definition to test. |
Returns boolean — true when the theme carries the generator's origin marker.
isOptionalSemantic(key): key is OptionalSemantic
Whether a colour key is an optional semantic capability.
| Parameter | Type | Description |
|---|---|---|
key | string | The colour key to test. |
Returns key is OptionalSemantic
isSelectionResolvable(themes, selection): boolean
Whether a selection can be resolved to a usable theme in a catalog.
A selection is resolvable when its family is registered in themes AND at
least one theme for that family resolves the requested mode (treating
"system" as the light variant for the check — the caller re-resolves the
concrete mode).
| Parameter | Type | Description |
|---|---|---|
themes | readonly ThemeDefinition<string>[] | — |
selection | ThemeSelectionState | — |
Returns boolean
isSettled(current, target, epsilon?): boolean
True when two positions are close enough to consider the thumb "settled".
| Parameter | Type | Description |
|---|---|---|
current | number | — |
target | number | — |
epsilon | number (optional) | — |
Returns boolean
isThemeMode(value): value is ThemeMode
Narrow an unknown value to a ThemeMode.
This is the single shared predicate for the light/dark/system axis. It is exported so that adapters which receive a mode from outside the type system — storage, cookies, cross-tab messages, element attributes — validate it the same way instead of each re-implementing the comparison.
| Parameter | Type | Description |
|---|---|---|
value | unknown | The value to test. |
Returns value is ThemeMode — true when value is a valid mode.
if (!isThemeMode(input)) {
emitDiagnostic(createDiagnostic({ code: "TV_MODE_INVALID", level: "warning", message: "..." }));
}isUsableTheme(theme): theme is ThemeDefinition<string>
Whether a value is a usable theme entry.
Deliberately lenient — the runtime needs a stable identity (name) and an
object to read meta/tokens from, not a fully-populated palette. A theme
with partial tokens is still a valid registration (the CSS-variable binding
simply emits what is present), so schema completeness is not required here.
| Parameter | Type | Description |
|---|---|---|
theme | unknown | — |
Returns theme is ThemeDefinition<string>
loadThemeRegistry(source): RegistryLoadResult
Read a generated theme registry from its source.
Statically: the module is never imported, evaluated or transpiled.
| Parameter | Type | Description |
|---|---|---|
source | string | The module's text. |
Returns RegistryLoadResult — The themes it registers, or a structured failure.
The shape recognised is the one themvora init writes: a themvora array of
defineTheme literals, a selection of family names, a sourceThemes array,
and a themes export combining them. A module outside that shape — including
a hand-written one — is reported as not-a-registry or
unsupported-construct, never partially guessed.
measureThemeContrast(theme): MeasuredPair[]
Measure every contract pair in a resolved theme.
The canonical measurement — the scorecard's text-contrast and ui-contrast
checks, the preset audit and the docs pages all read this, so a page cannot
show a ratio the gate disagrees with. Anything that renders contrast numbers
should call this rather than re-deriving them.
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme to measure. |
Returns MeasuredPair[] — One row per contract pair, in contract order.
mergePresetTokens(base, override?): ThemeTokens
Merge a partial token override into a base token set.
Each token group is merged shallowly, so override values replace individual keys while leaving unspecified keys from the base intact.
| Parameter | Type | Description |
|---|---|---|
base | ThemeTokens | The base token set. |
override | Partial<ThemeTokens> (optional) | Optional partial token groups to merge on top. |
Returns ThemeTokens — A new token set combining base and override.
mergeThemeDefinitions<Name extends string>(base, override): ThemeDefinition<Name>
Merge two theme definitions, deep-merging their meta and tokens.
override wins for scalar fields; meta and tokens are merged via
mergeTokens semantics.
| Parameter | Type | Description |
|---|---|---|
base | ThemeDefinition<Name> | Base definition (typically the inherited theme). |
override | ThemeDefinition<Name> | Override definition (typically the theme's own). |
Returns ThemeDefinition<Name> — A new merged definition. The inputs are not mutated.
mergeTokens(base, override): ThemeTokens | undefined
Merge two token objects, deep-merging the colors group and shallowly
merging every other group.
override wins over base. Within colors, an explicit undefined
value removes a key; nested color objects merge recursively. Groups not
present in either input are omitted from the result.
See also: flattenTokens, resolveTokens
| Parameter | Type | Description |
|---|---|---|
base | ThemeTokens | undefined | Base tokens (typically the inherited/extended theme's). |
override | ThemeTokens | undefined | Override tokens (typically the theme's own). |
Returns ThemeTokens | undefined — The merged tokens, or undefined when both inputs are empty.
migrateTheme(theme, options?): ThemeDefinition
Migrate a legacy theme to the current Themvora format using registered migrations.
See also: registerMigration
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | — |
options | MigrateOptions (optional) | — |
Returns ThemeDefinition
normalizeProvidedThemes<T extends ThemeDefinition<string>>(themes, previous?): readonly ProvidedThemeFamily<T>[]
Group a provider's theme collection into discoverable families.
Preserves the supplied order of both families and variants, keeps light/dark (and any other mode) as siblings rather than flattening them, and never mutates or extends the input — a family appears only if a theme for it was supplied.
See also: createProvidedThemesSource
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | The collection the provider was given, in registration order. |
previous | readonly ProvidedThemeFamily<T>[] (optional) | A previous derivation to reuse unchanged entries from. Passing the result of the last call keeps family and variant identities stable across ordinary provider updates. |
Returns readonly ProvidedThemeFamily<T>[] — The grouped collection, ordered by first appearance.
const families = normalizeProvidedThemes(runtime.themes);
const mint = families.find((family) => family.family === "mint");
mint?.variants.map((variant) => variant.tokens.colors?.background);normalizeThemeCatalog<T extends ThemeDefinition<string>>(themes): readonly T[]
Normalize a theme catalog.
Drops entries that are not usable themes, drops duplicate names (first
wins, matching the registry's deduplication), and — when nothing usable
remains — falls back to the canonical neutral themes. The input array is never
mutated.
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | undefined | The requested catalog, or undefined to request the fallback. |
Returns readonly T[] — A non-empty, deduplicated catalog.
parseCookieHeader(header): ParsedCookies
Minimal RFC 6265 header parser — enough for the four theme cookies.
See also: themvoraCookieNames, resolveThemeFromCookies
| Parameter | Type | Description |
|---|---|---|
header | string | — |
Returns ParsedCookies
parseThemeJson(text): ParsedThemeJson
Parse a theme document, tolerating comments and trailing commas.
| Parameter | Type | Description |
|---|---|---|
text | string | The document's text. |
Returns ParsedThemeJson — The parsed value and the masked source.
preferredInk(role, ctx): Oklch | null
The preferred ink for a role, resolved for the mode.
"light" and "dark" are the two ink families, not literal white and black: the light ink is the theme's near-white, the dark ink its near-black. A role that prefers light ink gets the near-white in both modes, which is what keeps a button label consistent across a mode switch.
| Parameter | Type | Description |
|---|---|---|
role | CoreColor | The role to resolve. |
ctx | PaletteContext | The generation context (for the neutral hue and chroma). |
Returns Oklch | null — The preferred ink, or null when the role has no preference.
prefersReducedMotion(): boolean
Requested motion profile. Reduced motion snaps instantly.
Returns boolean
provideThemeRuntime<T extends ThemeDefinition<string>>(runtime): void
Provides a Themvora runtime to the current Vue component subtree.
Call inside a component's setup scope (typically the app root) so
descendant composables can resolve it via useThemeRuntime.
See also: useThemeRuntime, ThemeProvider
| Parameter | Type | Description |
|---|---|---|
runtime | ThemeRuntime<T> | The runtime to make available to the subtree. |
Returns void
readBootstrapState<T extends ThemeDefinition<string>>(themes, target?): ThemeBootstrapState<T> | null
Reads the pre-paint bootstrap's state back off the DOM, validated against the theme registry.
See also: createThemeBootstrapScript
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | The registry the data-theme name is validated against. |
target | Element | null (optional) | The element to read from. Defaults to <html>. |
Returns ThemeBootstrapState<T> | null — The validated state, or null when there is no DOM, no
data-theme, or the name is not in the registry.
This is the read half of the bootstrap handoff. The blocking script writes
data-theme (resolved theme), data-theme-selection-mode /
data-theme-selection-family (the selection, which is not recoverable from
the resolved theme), data-theme-ready, and a
window.__THEMVORA_BOOTSTRAP__ payload.
It exists so a client runtime can adopt what was already painted instead
of re-deriving it: by the time a client renders, <html> is the authority on
what the visitor is looking at, and anything that re-resolves can disagree
with it. The result is validated against the registry rather than trusted as
an arbitrary string, so a stale or hand-written attribute cannot inject a
theme that does not exist.
readThemeDefinitions(source, options?): ThemeDefinitionReadResult
Read every defineTheme({ … }) literal in a source file.
defineTheme() returns its argument unchanged — it is a type-level helper, not a
transformation — so reading the literal is reading the theme. That is what
makes a static reader sufficient here, and it is why this function needs no
knowledge of variants, defaults or provenance: there are none to apply.
Broader than loadThemeRegistry, which requires the canonical registry's exports. A project may define themes in any file it likes; this finds the definitions wherever they are, and reports the ones it cannot read rather than skipping them.
It also reads generateTheme({ … }) calls whose argument is a literal object.
That is not executing project code: generateTheme is Themvora's own pure
generator, and calling it with data read from the file is the same thing the
application does at runtime. A call with any other argument is refused.
In strict mode every API name must come from bindings or namespaces; a
local function with a catalog's spelling is not the catalog.
| Parameter | Type | Description |
|---|---|---|
source | string | The file's text. |
options | ThemeDefinitionReadOptions (optional) | Verified bindings, namespaces and strictness. |
Returns ThemeDefinitionReadResult — The definitions found, and the candidates refused.
readTransportedConfig<T extends ThemeDefinition<string>>(): ThemeBootstrapConfig<T> | null
Reads the configuration a build integration transported to the runtime.
See also: resolveRuntimeOptions
Returns ThemeBootstrapConfig<T> | null — The transported configuration, or null when no integration ran.
A build integration (the Vite plugin, the Astro integration) puts the
ThemeBootstrapConfig projection of theme.config.ts on the global
scope before any application code runs. Reading it is what lets a provider
take no theme props — and it is the mechanism that makes "one declaration,
two consumers" true rather than aspirational.
globalThis rather than window, because the same read has to work during
SSR and prerender, where there is no window. The server entries set the
same global for exactly that reason.
registerMigration(step): void
Register a migration for the theme migration system.
See also: clearMigrations, migrateTheme
| Parameter | Type | Description |
|---|---|---|
step | MigrationStep | — |
Returns void
resetDiagnosticEmission(): void
Forget which diagnostics have already been emitted.
Deduplication is process-wide by design, which makes it stateful across tests. Call this between test cases so each one observes its own emissions.
Returns void
beforeEach(() => resetDiagnosticEmission());resolveEffectiveConfiguration<T extends ThemeDefinition<string>>(options): EffectiveConfiguration<T>
Resolve the effective selection + theme for a configuration update.
Precedence (shared by every adapter — there is no per-framework variant):
preserveand the previous selection is still resolvable → keep it. A catalog change that leaves the selection valid must not silently move the user to another theme.- Otherwise resolve from
defaultTheme/initialFamily/initialModeagainst the effective catalog. - An unknown requested family normalizes to a resolvable family and emits a
single
TV_THEME_FAMILY_UNKNOWNdiagnostic.
| Parameter | Type | Description |
|---|---|---|
options | { defaultTheme?: string; initialFamily?: string; initialMode?: ThemeMode; prefersDark?: boolean; preservePrevious?: boolean; previousSelection?: ThemeSelectionState; themes: readonly T[] } | Resolution inputs. |
Returns EffectiveConfiguration<T> — The effective selection and its theme.
resolveGeneratedTheme<T extends ThemeDefinition<string>>(themes, active?): T
Resolve the single generated theme registered with a provider, or throw.
The throwing counterpart of findGeneratedTheme, for call sites that need a theme rather than a status — the framework accessors, which surface the failure to the caller.
See also: `- isGeneratedTheme
- findGeneratedTheme`
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | The themes registered with the provider. |
active | T (optional) | The currently active theme, used to disambiguate multiple generated themes. |
Returns T — The resolved generated theme.
resolveIconOptions<T>(icons?): OverlayScrollbarOptions
Map an icons group onto the engine's flat icon options, so every adapter
resolves the group the same way. Only defined entries are copied.
| Parameter | Type | Description |
|---|---|---|
icons | ScrollbarIconOptions<T> (optional) | The icons group (or undefined). |
Returns OverlayScrollbarOptions — Flat arrowIcon / arrow*Icon / iconSize values.
resolveInitialTheme<T extends ThemeDefinition<string>>(options): InitialThemeResolution<T>
Resolves the initial theme and selection for a runtime bootstrap.
Combines defaultTheme, family, mode, and prefersDark into a
concrete theme, resolving "system" mode against prefersDark for the
theme lookup while keeping the "system" mode in the returned selection.
See also: resolveSelection, resolveThemeName
| Parameter | Type | Description |
|---|---|---|
options | ResolveInitialThemeOptions<T> | Resolution inputs. |
Returns InitialThemeResolution<T> — The resolved theme and selection.
resolveRuntimeOptions<T extends ThemeDefinition<string>>(options?): Partial<ThemeRuntimeOptions<T>>
Merges the transported configuration under a provider's own options.
See also: readTransportedConfig
| Parameter | Type | Description |
|---|---|---|
options | Partial<ThemeRuntimeOptions<T>> (optional) | The provider's own options. These win, so a local override stays possible. |
Returns Partial<ThemeRuntimeOptions<T>> — The options a runtime should be created from.
The order is the contract: transported first, provider second. A provider
that supplies themes is overriding the application configuration, which is
legitimate for a test or a storybook but is otherwise the duplication this
whole mechanism exists to remove.
Provider options whose value is undefined are dropped rather than spread.
That is not a detail — Vue and Svelte hand the provider an object containing
every declared prop, with undefined for the ones the app did not pass, so
a plain spread would overwrite the transported value with undefined and the
provider would silently fall back to the built-in themes.
themes is always resolved to a non-empty array. createThemeRuntime falls
back to the built-in themes only when themes is undefined, so an empty
array — a provider given themes={[]}, or a config whose registry was
filtered to nothing — would otherwise produce a runtime with no registry at
all, which throws on the first selection.
An explicit empty array counts as not set, not as "no themes": the Web
Components provider parses an absent themes attribute into [], and
treating that as an override would shadow the transported registry with
nothing.
const resolved = resolveRuntimeOptions<T>(props);
const runtime = createThemeRuntime(resolved);resolveScheduledThemePair<T extends ThemeDefinition<string>>(themes, options, current?): { dark: T | null; light: T | null }
Resolve the scheduled light/dark themes from the configured options and
the currently selected theme. Priority: explicit lightTheme/darkTheme
→ same-family counterpart of the current theme → neutral light/dark.
Shared by createThemeSchedule and createScheduledPlugin.
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | — |
options | ScheduledThemePairInput<T> | — |
current | { meta?: { family?: string } } (optional) | — |
Returns { dark: T | null; light: T | null }
resolveScopedTheme<T extends ThemeDefinition<string>>(themes, selection, prefersDark?): T
Resolve a scoped selection against a theme list. themes should already be
the combined source: local themes FIRST, then the parent runtime's registry.
Resolution order:
- exact theme-name match (local wins),
- a name that matches a family → that family's theme for the mode,
- explicit family + mode → exact match, else the family's light theme, else the family's first theme,
- the first theme in the list as a last-resort fallback.
The resolved definition has its extends chain merged (like resolveTheme)
so scoped CSS variables include every inherited token.
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | — |
selection | ScopedThemeSelection | — |
prefersDark | boolean (optional) | — |
Returns T
resolveScopedThemePrePaint<T extends ThemeDefinition<string>>(themes, selection, options?): ScopedThemePrePaint
Resolve everything a scope needs for its FIRST PAINT, generically from its
theme data (no hardcoded colors — any user's scoped themes produce the same
result). When the selection is OS-dependent (a system mode, or a family /
boundary scope currently following a system selection), it returns a
@media (prefers-color-scheme: dark) CSS block so the scoped region renders
light OR dark correctly before hydration, with the live binding taking over
through its own inline variables afterwards.
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | — |
selection | ScopedThemeSelection | — |
options | ScopedThemePrePaintOptions (optional) | — |
Returns ScopedThemePrePaint
resolveScopeTransition(parent, local): ThemeTransitionOptions | undefined
Merge a scope's transition over its parent runtime's transition.
The inheritance model is ThemeProvider transition → ThemeScope → inherited defaults → local overrides:
local === undefined→ inherit the parent's configuration unchanged,local === true→ inherit the parent's configuration unchanged,local === false→ transitions disabled for this scope only,localobject → merged over the parent's (local keys win).
Frameworks use this so <ThemeScope transition={{ duration: 200 }}> flips
just the duration without the user having to repeat the provider's easing /
preset.
| Parameter | Type | Description |
|---|---|---|
parent | ThemeTransitionOptions | undefined | — |
local | boolean | ThemeTransitionOptions | undefined | — |
Returns ThemeTransitionOptions | undefined
resolveScrollbarOptions(grouped?, flat?): OverlayScrollbarOptions
Merge grouped settings (plus any deprecated flat aliases) into one canonical
OverlayScrollbarOptions object.
Only keys that are actually defined are copied, so an explicitly-undefined
value never overrides a core default, and the returned object is always a
fresh one (the inputs are never mutated).
| Parameter | Type | Description |
|---|---|---|
grouped | ScrollbarGroupedOptions (optional) | behavior / appearance / scope groups. |
flat | ScrollbarFlatOptions (optional) | Deprecated flat aliases (and framework-specific values such as iconSize); any defined key here wins over the same key in a group. |
Returns OverlayScrollbarOptions — A canonical options object for createOverlayScrollbar.
resolveSelectedTheme<T extends ThemeDefinition<string>>(themes, selection): T
Resolve the registered theme that best matches a selection.
Prefers an exact family + mode match, then any theme in the family, then any theme of the requested mode, then the first registered theme. Never throws; the fallback chain guarantees a result for non-empty theme lists.
See also: resolveThemeName, ThemeSelection
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | Registered themes to search. |
selection | ThemeSelection | The family + mode selection to match. |
Returns T — The selected theme definition.
resolveSelection<T extends ThemeDefinition<string>>(options): ThemeSelectionState
Resolves a selection state from configuration inputs.
Priority: persistedSelection wins; otherwise initialFamily (family or
variant), then defaultTheme (family or variant), then the first theme.
See also: resolveInitialTheme, resolveThemeReference
| Parameter | Type | Description |
|---|---|---|
options | ResolveSelectionOptions<T> | Resolution inputs. |
Returns ThemeSelectionState — The resolved selection (family + mode).
resolveSelectionTheme<T extends ThemeDefinition<string>>(options): SelectionThemeResolution<T>
Resolves the theme that matches an existing selection state.
Convenience wrapper around resolveInitialTheme for the common case of re-applying a persisted or scoped selection.
See also: resolveSelection, resolveSelectedTheme
| Parameter | Type | Description |
|---|---|---|
options | ResolveSelectionThemeOptions<T> | Resolution inputs. |
Returns SelectionThemeResolution<T> — The matching theme and the normalized selection.
resolveSolarLocation(input?): ResolvedSolarLocation
Resolve the coordinates a solar calculation should use.
Priority: explicit latitude/longitude → explicit timeZone →
browser timezone auto-detection → DEFAULT_TIMEZONE_LOCATION.
| Parameter | Type | Description |
|---|---|---|
input | SolarLocationInput (optional) | — |
Returns ResolvedSolarLocation
resolveTheme<Name extends string>(themes, themeName, resolveTokenRefs?): ThemeDefinition<Name>
Resolve a theme definition to its fully inherited form.
Walks the extends chain (multiple parents merge in order), producing the
effective meta and tokens. When resolveTokenRefs is true, token
references (${token.path}) and derived expressions are also resolved.
See also: mergeThemeDefinitions, resolveThemeRegistry
| Parameter | Type | Description |
|---|---|---|
themes | readonly ThemeDefinition<Name>[] | All registered themes. |
themeName | Name | Name of the theme to resolve. |
resolveTokenRefs | boolean (optional) | Whether to resolve token references in the result. Default true. |
Returns ThemeDefinition<Name> — The resolved theme definition.
resolveThemeFromCookies<T extends ThemeDefinition<string>>(options): InitialThemeResolution<T>
SSR-first theme resolution. Reads the four theme cookies from the request,
rejects them when the config fingerprint is stale, and resolves the initial
theme for the effective selection — exactly like @themvora/next's
getInitialThemeState.
The resolved <html> state (theme name, family, mode) can then be rendered
server-side so the browser paints already themed.
See also: createNuxtThemeBootstrapScript, parseCookieHeader
| Parameter | Type | Description |
|---|---|---|
options | ResolveThemeFromCookiesOptions<T> | — |
Returns InitialThemeResolution<T>
resolveThemeName<Name extends string>(themes, family, mode, prefersDark?): Name
Resolve the theme name that best matches a family + mode selection.
Looks up the theme in family whose mode matches the requested mode,
honoring prefersDark when mode is "system". Falls back to the
family's light theme, then the family's first theme, then the first
theme overall.
See also: getThemeFamily, getThemeMode, resolveSelectedTheme
| Parameter | Type | Description |
|---|---|---|
themes | readonly ThemeDefinition<Name>[] | Registered themes to search. |
family | string | Family to resolve within. |
mode | ThemeMode | Requested mode; "system" resolves via prefersDark. |
prefersDark | boolean (optional) | Whether the visitor prefers dark mode. Used only when mode is "system". Default false. |
Returns Name — The resolved theme name.
resolveThemeOverride<T extends ThemeDefinition<string>>(themes, override, base): ThemeSelectionState | null
Resolve an override against the provider's themes.
Pure: no side effects, no state. Returns a complete selection (both fields
filled) or null when the override cannot be satisfied — the caller decides
whether to report and ignore or to treat it as absent.
A string is a theme name and must match exactly. An object is a
family/mode request; a missing field is inherited from base.
See also: ThemeOverride
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | The provider's registered themes. |
override | ThemeOverride<T["name"]> | undefined | The requested override, or undefined. |
base | ThemeSelectionState | The selection the provider would use without an override. Used to fill in a partially specified request. |
Returns ThemeSelectionState | null — The resolved selection, or null when absent or unresolvable.
// `themes` is whatever registry the provider was given.
const themes = getBuiltInThemes();
const selection = { family: "mint", mode: "light" };
resolveThemeOverride(themes, "mint-dark", selection); // { family: "mint", mode: "dark" }
resolveThemeOverride(themes, { family: "mint" }, selection); // keeps base.mode
resolveThemeOverride(themes, "nope", selection); // nullresolveThemeReference<T extends ThemeDefinition<string>>(themes, reference, options?): ResolvedThemeReference<T> | null
Resolve a theme reference against a provider's catalog.
See also: resolveThemeOverride, resolveSelection
| Parameter | Type | Description |
|---|---|---|
themes | readonly T[] | The themes the provider was given. A reference that is not in this list does not resolve — the global preset catalog is never consulted. |
reference | string | null | undefined | A variant name, a family name, or nothing. |
options | ResolveThemeReferenceOptions (optional) | Mode used for a family reference. |
Returns ResolvedThemeReference<T> | null — The resolution, or null when the reference names nothing available.
An exact variant name wins over a family name. A theme whose name equals
another theme's family is therefore addressable as a variant — the explicit,
more specific reading — and the family form of the other family keeps
working. The two namespaces are otherwise independent: a family is
meta.family ?? "default", a variant is name.
// `themes` is whatever registry the provider was given.
const themes = getBuiltInThemes();
resolveThemeReference(themes, "cocoa-dark"); // { kind: "variant", mode: "dark", … }
resolveThemeReference(themes, "cocoa", { mode: "dark" }); // { kind: "family", … cocoa-dark }
resolveThemeReference(themes, "nope"); // nullresolveThemeRegistry<T extends ThemeDefinition<string>>(options?): readonly T[]
Resolves the effective theme list for a registry configuration.
Returns the provided themes when non-empty; otherwise falls back to the built-in themes.
See also: ThemeRegistry, getBuiltInThemes
| Parameter | Type | Description |
|---|---|---|
options | ThemeRegistryOptions<T> (optional) | Registry configuration. |
Returns readonly T[] — The effective theme definitions.
resolveTokens(tokens): ThemeTokens
Resolve a theme's token groups, evaluating expressions and references into concrete values.
See also: flattenTokens, evaluateExpression
| Parameter | Type | Description |
|---|---|---|
tokens | ThemeTokens | — |
Returns ThemeTokens
restoreNativeScrollbar(): void
Restore the platform's native scrollbars, discarding any outstanding claims.
Undoes the hiding completely: the tv-scrollbar class (and the
tv-scrollbar-ready phase marker) come off <html>, and every hiding
stylesheet is removed. Safe to call at any time and idempotent — a page that
never hid anything is left untouched.
This is what makes the overlay's lifecycle symmetric. Without it, unmounting the overlay left the page with the native bar still hidden and nothing to replace it: an invisible scrollbar, not a native one.
It is also a hard reset: the claim count drops to zero, so an overlay that
outlives the call no longer keeps the native bar hidden on its own. That is
the point — it is the escape hatch for a page that has decided the overlay is
gone (a teardown, a framework's beforeunload, a test), and it is why the
count cannot drift upwards forever.
Returns void
runThemeAnimation(input): void
Run the animation for one theme change. Called by the CSS-variables binding only when the Transition Planner produced a non-null plan.
| Parameter | Type | Description |
|---|---|---|
input | ThemeAnimationInput | — |
Returns void
scanForTransition(root, properties): HTMLElement[]
Collect elements that both (a) are visible and (b) actually use one of the provided CSS properties. Runs only when non-color groups are animating.
| Parameter | Type | Description |
|---|---|---|
root | Node | — |
properties | string[] | — |
Returns HTMLElement[]
scopeToCSSVariables(themeVars, prefix?): Record<string, string>
Mirror the scoped binding's aliases (the --color-* / --radius-* tokens
Tailwind-style utilities resolve against) so styling utilities on scoped
elements use the scoped theme's values, not the page theme's.
| Parameter | Type | Description |
|---|---|---|
themeVars | Record<string, string> | — |
prefix | string (optional) | — |
Returns Record<string, string>
scoreTheme(theme): PresetScore
Score a theme against the nine preset quality checks.
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme to score. |
Returns PresetScore — The scorecard.
simulateCVD(hex, type): string
Simulate how a color appears to someone with the given color vision deficiency.
Converts the color to linear RGB, transforms it through the LMS cone space, collapses the affected cone channel (or, for achromatopsia, reduces to luminance), and converts back to a hex string. Non-hex input is returned unchanged.
| Parameter | Type | Description |
|---|---|---|
hex | string | The hex color to simulate. |
type | CVDType | The CVD type to simulate. |
Returns string — The simulated hex color, or hex unchanged when it is not a hex
color.
simulateThemeForCVD(theme, type): ThemeDefinition
Produce a copy of a theme whose color tokens are simulated for the given color vision deficiency.
Every hex color in tokens.colors is passed through simulateCVD;
non-color tokens and non-hex values are preserved. The returned theme is a
new object and the input is not mutated. Themes without color tokens are
returned unchanged.
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme definition to simulate. |
type | CVDType | The CVD type to simulate. |
Returns ThemeDefinition — A new theme definition with simulated color tokens.
systemModeCSSTemplate(light, dark): string
Generate the stylesheet that resolves a "system" selection with CSS alone —
no script and no inline style.
See also: darkModeCSSTemplate
| Parameter | Type | Description |
|---|---|---|
light | Record<string, string> | The light theme's CSS variables. |
dark | Record<string, string> | The dark theme's CSS variables. |
Returns string — Two media blocks, one per scheme, both targeting :root, escaped
for <style>-element content exactly as darkModeCSSTemplate is.
Use this instead of inlining the resolved variables whenever the mode is
"system". The two cannot be combined: an inline style on <html>
outranks any stylesheet rule, so a page that inlines the light variables and
also emits a dark media block paints light whatever the OS prefers. Measured
on a production build with page scripts blocked and the OS set to dark, that
combination painted rgb(248, 250, 252) (light); emitting both media blocks
and no inline variables painted rgb(2, 6, 23).
prefers-color-scheme: light also matches when the visitor has expressed no
preference — light is the specified default — so the light block doubles as
the no-preference branch.
themeOverrideKey(override, themes?): string | null
The semantic identity of an override, for change detection.
Two overrides with the same key request the same theme, even when they are
different objects — which is the normal case for an inline
themeOverride={{ family: "mint" }} that is rebuilt on every render. Built
from resolved primitives only: no object stringification, no identity.
Pass the provider's catalog to canonicalise a theme name against the
family and mode it resolves to, so "mint-dark" and
{ family: "mint", mode: "dark" } compare equal — they are the same request
written two ways, and re-applying one because the other was spelled
differently is exactly the churn this function exists to prevent. Without a
catalog the name form keys on the name alone.
A partially specified request ({ family: "mint" }) keys on what was asked
for, never on the base selection it would inherit: otherwise a manual mode
change would make an unchanged prop look like a new request and re-assert the
family.
See also: resolveThemeOverride
| Parameter | Type | Description |
|---|---|---|
override | ThemeOverride<string> | undefined | The override to key. |
themes | readonly ThemeDefinition<string>[] (optional) | The provider's themes, used to canonicalise a theme name. |
Returns string | null — A stable string, or null when there is no override.
themeToCssDocument(theme): string
Render a theme, or a light/dark pair, as a CSS custom-property document.
This is the canonical formatting for Themvora's :root document convention,
and the only place it exists: the CLI's export --format css and the VS Code
extension's Copy CSS Variables both call it, so the CSS a user copies is the
CSS the CLI writes.
A single theme is emitted under CSS_ROOT_SELECTOR. A pair is emitted as
the light theme under :root followed by the dark theme under
CSS_DARK_SELECTOR.
Output is deterministic: the variable order comes from themeToCSSVariables, which emits token groups in a fixed order, so the same theme always produces byte-identical CSS.
See also: themeToCSSVariables
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition<string> | ThemeCssPair | A theme definition, or a { light, dark } pair. |
Returns string — The document, ending with a newline.
const { light, dark } = generateTheme({ seed: "#4f46e5" });
const css = themeToCssDocument({ light, dark });
// :root { --theme-color-background: #fbfbff; … }
// .dark, [data-theme="dark"] { … }themeToCSSVariables(theme, options?): Record<string, string>
Flatten a theme's semantic tokens into CSS custom properties
(--theme-*), optionally filtered by token group.
See also: flattenTokens, ThemeToCSSVariablesOptions
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | Theme whose tokens are flattened. |
options | ThemeToCSSVariablesOptions (optional) | Emission options (prefix, group filter). |
Returns Record<string, string> — A flat map of CSS custom property name → value.
Pass { groups: ["colors"] } to emit only specific token groups.
const vars = themeToCSSVariables(theme); // { "--theme-color-background": "#fff", ... }toBootstrapConfig<T extends ThemeDefinition<string>>(config): ThemeBootstrapConfig<T>
Projects a ThemvoraConfig down to what crosses to the browser.
See also: ThemeBootstrapConfig
| Parameter | Type | Description |
|---|---|---|
config | ThemvoraConfig<T> | The full application configuration. |
Returns ThemeBootstrapConfig<T> — The transported projection.
Copies the serializable runtime options as well as the bootstrap fields. A
field omitted here is not merely unused in the browser — it is replaced by a
default, which is how a declared transition: { enabled: false } still
produced a view transition on every theme change. See
ThemeBootstrapConfig.
useEffectiveThemeMode(): Ref<"light" | "dark">
Reactive ref of the mode actually applied — "light" or "dark", never
"system".
Render this when a control states the current appearance. useThemeMode
reports what the visitor asked for, which does not move at a sunrise/sunset
transition and stays "system" for as long as that choice stands — so a label
bound to it kept announcing the old mode while the page changed colour.
Call inside Vue setup scope within a <ThemeProvider>. Subscribes to the
appearance (store and effective-selection channels) and is cleaned up on
unmount.
See also: useThemeMode, useThemeSchedule
Returns Ref<"light" | "dark"> — A Ref holding the applied mode.
useProvidedThemes<T extends ThemeDefinition<string>>(): Ref<readonly ProvidedThemeFamily<T>[], readonly ProvidedThemeFamily<T>[]>
Reactive ref of the themes this provider was given, grouped by family.
Returns exactly the collection supplied to the nearest <ThemeProvider> —
not the built-in catalog, and not every theme in the project. The ref updates
when the provider's themes prop changes, when a theme pack is installed, or
when the registry is mutated, and it is cleaned up on unmount.
<script setup>
const families = useProvidedThemes();
</script>
<template>
<section v-for="family in families" :key="family.id">
<h3>{{ family.name }}</h3>
<button v-for="variant in family.variants" :key="variant.name">
{{ variant.mode }}
</button>
</section>
</template>See also: useTheme
Returns Ref<readonly ProvidedThemeFamily<T>[], readonly ProvidedThemeFamily<T>[]> — A ref holding the provider's theme families, in supplied order.
useTheme<T extends ThemeDefinition<string>>(): { effectiveMode: Ref<"light" | "dark", "light" | "dark">; family: Ref<string, string>; mode: Ref<ThemeMode, ThemeMode>; setFamily: __type(nextFamily: string): void; setMode: __type(nextMode: ThemeMode): void; theme: Ref<T, T>; toggleTheme: __type(): void }
Reactive access to the active theme, mode, and family plus selection controls.
Call inside Vue setup scope within a <ThemeProvider>. Returns reactive
refs for theme, mode, and family, along with setMode, setFamily,
and toggleTheme helpers that operate on the runtime's selection.
See also: useThemeValue, useThemeMode, useEffectiveThemeMode, useThemeFamily
Returns { effectiveMode: Ref<"light" | "dark", "light" | "dark">; family: Ref<string, string>; mode: Ref<ThemeMode, ThemeMode>; setFamily: __type(nextFamily: string): void; setMode: __type(nextMode: ThemeMode): void; theme: Ref<T, T>; toggleTheme: __type(): void } — An object of reactive state and selection helpers.
const { theme, mode, family, setMode, toggleTheme } = useTheme();useThemeBatch(): __type(callback: __type(): void): void
Returns a function that batches multiple runtime mutations into a single history entry and notification.
Call inside Vue setup scope within a <ThemeProvider>.
See also: useThemeSnapshot, useTheme
Returns __type(callback: __type(): void): void — A batch function taking a callback to run inside the batch.
useThemeFamily(): Ref<string, string>
Reactive ref of the current theme family.
Call inside Vue setup scope within a <ThemeProvider>. The returned ref
tracks both store and selection changes and is cleaned up on unmount.
See also: useThemeMode, useTheme
Returns Ref<string, string> — A Ref holding the current theme family.
useThemeHistory<T extends ThemeDefinition<string>>(): { canRedo: Ref<boolean, boolean>; canUndo: Ref<boolean, boolean>; clear: __type(): void; history: Ref<readonly { theme: UnwrapRef<T>; timestamp: number }[], readonly HistoryEntry<T>[] | readonly { theme: UnwrapRef<T>; timestamp: number }[]>; jump: __type(index: number): void; redo: __type(): void; undo: __type(): void }
Reactive access to the runtime's theme history (undo/redo).
Call inside Vue setup scope within a <ThemeProvider>. Returns reactive
canUndo, canRedo, and history refs plus undo, redo, clear, and
jump actions that operate on the runtime's history.
See also: useThemeSnapshot, useThemeRestore, useThemeBatch
Returns { canRedo: Ref<boolean, boolean>; canUndo: Ref<boolean, boolean>; clear: __type(): void; history: Ref<readonly { theme: UnwrapRef<T>; timestamp: number }[], readonly HistoryEntry<T>[] | readonly { theme: UnwrapRef<T>; timestamp: number }[]>; jump: __type(index: number): void; redo: __type(): void; undo: __type(): void } — An object of reactive history state and actions.
useThemeLifecycle(): { on: __type(event: keyof ThemeLifecycleEventMap<ThemeDefinition<string>>, listener: __type(data: unknown): void): __type(): void }
Returns an object for subscribing to runtime lifecycle events.
Call inside Vue setup scope within a <ThemeProvider>.
See also: useThemeRuntime, useTheme
Returns { on: __type(event: keyof ThemeLifecycleEventMap<ThemeDefinition<string>>, listener: __type(data: unknown): void): __type(): void } — An object with an on method to register a lifecycle listener.
useThemeMode(): Ref<ThemeMode, ThemeMode>
Reactive ref of the current theme mode (system, light, or dark).
Call inside Vue setup scope within a <ThemeProvider>. The returned ref
tracks both store and selection changes and is cleaned up on unmount.
See also: useThemeFamily, useTheme
Returns Ref<ThemeMode, ThemeMode> — A Ref holding the current mode.
useThemePacks(): __type(pack: ThemePack<any>): void
Returns a function that installs a theme pack onto the runtime.
Call inside Vue setup scope within a <ThemeProvider>.
See also: useThemeRuntime, useTheme
Returns __type(pack: ThemePack<any>): void — A function taking a theme pack to install.
useThemeRestore(): __type(snapshot: ThemeRuntimeSnapshot<ThemeDefinition<string>>): void
Returns a function that restores the runtime to a previously captured snapshot.
Call inside Vue setup scope within a <ThemeProvider>.
See also: useThemeSnapshot
Returns __type(snapshot: ThemeRuntimeSnapshot<ThemeDefinition<string>>): void — A function taking a snapshot to restore.
useThemeRuntime<T extends ThemeDefinition<string>>(): ThemeRuntime<T>
Resolves the active Themvora runtime from the Vue injection context.
Call inside Vue setup scope, within a component that is a descendant of a
<ThemeProvider> (or after provideThemeRuntime).
See also: provideThemeRuntime, ThemeProvider, useThemeValue
Returns ThemeRuntime<T> — The injected runtime.
const runtime = useThemeRuntime();
runtime.selection.setMode("dark");useThemeSchedule<T extends ThemeDefinition<string>>(): ThemeScheduleController
Reactive access to the runtime's sunrise/sunset scheduling controller.
Requires the runtime (or <ThemeProvider>) to be created with the
scheduled option. The returned state ref tracks enabled, status,
active, sunrise/sunset and the next transition; enable()/disable()
/set() control the engine.
<script setup lang="ts">
const schedule = useThemeSchedule();
</script>Returns ThemeScheduleController
useThemeSnapshot(): __type(): ThemeRuntimeSnapshot<ThemeDefinition<string>>
Returns a function that captures a serializable snapshot of the runtime's current state.
Call inside Vue setup scope within a <ThemeProvider>.
See also: useThemeRestore
Returns __type(): ThemeRuntimeSnapshot<ThemeDefinition<string>> — A function returning the current runtime snapshot.
useThemeTokens<T extends ThemeDefinition<string>>(): Ref<ThemeTokens | undefined, ThemeTokens | undefined>
Reactive ref of the active theme's token group.
Call inside Vue setup scope within a <ThemeProvider>. The returned ref
updates as the active theme changes and is cleaned up on unmount.
See also: useThemeValue
Returns Ref<ThemeTokens | undefined, ThemeTokens | undefined> — A Ref holding the active theme's tokens, or undefined when the
theme defines none.
useThemeValue<T extends ThemeDefinition<string>>(): Ref<T, T>
Reactive ref of the currently selected theme definition.
Call inside Vue setup scope within a <ThemeProvider>. The returned ref
updates whenever the active theme changes and is cleaned up on unmount.
See also: useTheme, useThemeTokens
Returns Ref<T, T> — A Ref holding the active theme.
validateTheme(theme, options?): ValidationResult
Validate a theme definition against the Themvora schema.
Checks that the definition declares a tokens object and that every required
semantic colour token is present. It deliberately does not resolve token
references and does not check contrast: unresolved references are reported by
token resolution (which throws), and contrast has its own validator,
validateThemeContrast.
Returns issues rather than throwing, so a caller can report every problem at once — the CLI does exactly this.
See also: ValidationIssue, generateTheme
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme definition to validate. |
options | ValidateThemeOptions (optional) | Optional registry used to resolve the theme by name first. |
Returns ValidationResult — { valid, issues }, where valid is true when issues is empty.
validateThemeContrast(theme, options?): ContrastValidationResult
Validate a theme's semantic color pairs against WCAG contrast thresholds.
Checks the standard foreground/background pairs (e.g. foreground on
background, primaryForeground on primary) and reports each pair's
ratio and whether it passes WCAG AA/AAA for normal and large text. Pairs
whose colors are missing or not hex are skipped. The theme is considered
valid when every checked pair passes WCAG AA for normal text.
See also: getContrastRatio
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme definition to check. |
options | ValidateThemeContrastOptions (optional) | Optional configuration. |
Returns ContrastValidationResult — A ContrastValidationResult with per-pair checks.
validateThemeLevels(theme, options?): LevelIssue[]
Run the internal validation levels over a theme definition.
| Parameter | Type | Description |
|---|---|---|
theme | ThemeDefinition | The theme to validate. |
options | ValidateThemeLevelsOptions (optional) | Which levels to run and which CVD types to diagnose. |
Returns LevelIssue[] — Every issue found, across the requested levels.
Classes
class ThemeError
Extends Error
The error type thrown by Themvora for theme-related failures.
Extends the native Error and sets name to "ThemeError" so callers can
distinguish Themvora failures from other errors via instanceof or the
name property. The message carries the human-readable failure detail.
When the failure corresponds to a diagnostic, the error also carries the stable ThemeError.code and its structured context, so a caller can branch on the code rather than matching on prose. Both are optional: the single-argument form remains valid.
See also: ThemeError.fromDiagnostic
| Member | Type | Description |
|---|---|---|
constructor | ThemeError | — |
cause (optional) | unknown | — |
readonly code (optional) | ThemeDiagnosticCode | Stable diagnostic code, or undefined for a plain Themvora failure. |
readonly context (optional) | ThemeDiagnosticContext | Structured context describing the failure, when available. |
message | string | — |
name | string | — |
stack (optional) | string | — |
stackTraceLimit | number | The Error.stackTraceLimit property specifies the number of stack frames collected by a stack trace (whether generated by new Error().stack or Error.captureStackTrace(obj)). The default value is 10 but may be set to any valid JavaScript number. Changes will affect any stack trace captured after the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. |
captureStackTrace | void | — |
fromDiagnostic | ThemeError | — |
prepareStackTrace | any | — |
const diagnostic = createDiagnostic({
code: "TV_MODE_INVALID",
level: "warning",
message: 'setMode() received an unknown mode "purple".',
context: { api: "setMode", property: "mode", received: "purple" },
});
// A caller that treats this as fatal rather than recoverable:
throw ThemeError.fromDiagnostic(diagnostic);class ThemeRegistry<T extends ThemeDefinition>
A collection of registered theme definitions with deduplication, inheritance-ready metadata stamps, and family queries.
The registry stores theme definitions; resolution of extends chains
and token references happens separately via resolveTheme.
| Member | Type | Description |
|---|---|---|
constructor | ThemeRegistry<T> | — |
themes | void | — |
batch | void | — |
clear | void | — |
destroy | void | — |
get | T | undefined | — |
getFamilies | string[] | — |
getThemesByFamily | T[] | — |
has | boolean | — |
list | readonly T[] | — |
register | boolean | — |
registerMany | number | — |
replace | boolean | — |
subscribe | __type(): void | — |
unregister | boolean | — |
use | void | — |
Interfaces
AccessibilityPluginOptions
Options for createAccessibilityPlugin.
| Member | Type | Description |
|---|---|---|
level (optional) | "AA" | "AAA" | Target WCAG contrast level. |
onViolation (optional) | __type(result: { checks: ContrastCheck[]; themeName: string }): void | Invoked with the theme name and failing contrast checks whenever a contrast violation is detected. |
warnOnly (optional) | boolean | When true, contrast violations are reported at warning level; when false, they are reported at error level. Default true. |
ActionProminence
The prominence of the primary action fill against the canvas.
| Member | Type | Description |
|---|---|---|
anchored | boolean | Whether the fill is a pinned brand anchor rather than a generated colour. Read from meta.generation.anchored, which the recipe builder records. When true, passes is reported but not enforced: the brand colour is the brand's, and moving it would trade identity for a number. |
floor | number | The floor a generated fill is held to. |
passes | boolean | Whether the fill is prominent enough to read as a control. |
ratio | number | The ratio between the fill and the canvas. |
AdapterPlugin
A plugin that refines or transforms the output of a library adapter.
refine receives the refined semantic state and may return updates to it;
transform receives the generated library variables and must return the
final set. Both hooks are optional.
| Member | Type | Description |
|---|---|---|
id (optional) | string | Optional identifier for the plugin. |
refine (optional) | void | Record<string, unknown> | — |
transform (optional) | Record<string, string> | — |
AdapterPluginContext
The context passed to an adapter plugin's hooks. Describes how faithfully the adapter should reproduce the target library's native feel and the current theme mode.
| Member | Type | Description |
|---|---|---|
mode | "light" | "dark" | "system" | undefined | The current theme mode, or undefined when no mode is resolved. |
strategy | AdapterStrategy | How faithfully the adapter reproduces the target library's native feel. |
AdapterRegistration
A successful registration returned by AdapterRegistry.use. Calling
dispose() removes exactly the adapter instance it was created for — but
only when its own reference count drops to zero. This makes composition
(React Strict Mode, Svelte lifecycles, nested providers) deterministic.
See also: AdapterRegistry
| Member | Type | Description |
|---|---|---|
readonly id | string | The registered adapter's id. |
dispose | void | — |
AdapterRegistry<T extends ThemeDefinition>
The runtime-owned adapter registry. Registering an adapter installs it; the runtime notifies the registry when the active theme changes.
use is idempotent per adapter instance and returns an AdapterRegistration
whose dispose() uninstalls deterministically:
const handle = runtime.adapters.use(adapter);
// ... later
handle.dispose();See also: ThemeAdapter
| Member | Type | Description |
|---|---|---|
destroy | void | — |
list | readonly ThemeAdapter<T>[] | — |
unuse | boolean | — |
use | AdapterRegistration | — |
AnimationsPluginOptions
Options for createAnimationsPlugin.
| Member | Type | Description |
|---|---|---|
element (optional) | HTMLElement | Element to which the transition is applied. Defaults to document.documentElement in browser environments; null (no-op) in non-browser environments. |
transition (optional) | ThemeTransitionOptions | CSS transition applied to the target element during theme changes. When omitted, a default transition of 300ms ease-in-out over all properties is used, with View Transitions explicitly disabled. |
BrandReferenceColor
One colour from a brand's reference material.
| Member | Type | Description |
|---|---|---|
classification | BrandColorClass | How the generator treats it. |
color | string | The exact value, verbatim from the source. |
label | string | What the source calls this colour, e.g. "Blurple" or "Background 1". |
mode (optional) | PresetMode | Restrict the anchor to one mode. Omitted means both. |
official | boolean | Whether the brand publishes this as part of its identity. |
source | string | Where the value came from — specific enough to re-check. |
themeRole (optional) | CoreColor | The Themvora role this value anchors, when it is pinned. Present only on ANCHOR entries the generator uses directly. An ANCHOR without a themeRole is still exact — it informs the identity — but it does not map onto a Themvora role. |
BrandSource
The reference material behind a brand preset.
| Member | Type | Description |
|---|---|---|
colors | readonly BrandReferenceColor[] | Every reference colour, classified. |
hasDesignSystem | boolean | Whether the brand publishes a full token system rather than a few colours. |
hasLightDark | boolean | Whether the brand publishes light/dark variants of its system. |
kind | BrandSourceKind | How strong the source is. |
name | string | The brand's name. |
notes (optional) | readonly string[] | Caveats — legal, licensing, or fidelity limits. |
sourceUrl | string | Where to re-check the values. |
BroadcastChannelLike<T>
A minimal subset of the BroadcastChannel API used by the broadcast
adapters. Accepts any object with the same shape, enabling custom or
polyfilled channels.
| Member | Type | Description |
|---|---|---|
addEventListener | void | — |
close | void | — |
postMessage | void | — |
removeEventListener | void | — |
BroadcastPluginOptions
Options for createBroadcastPlugin.
| Member | Type | Description |
|---|---|---|
adapter (optional) | { destroy?: void; onMessage: void; postMessage: void } | null | Custom broadcast adapter. When omitted, a BroadcastChannel-based adapter is used when available; otherwise the plugin is inert. Pass null to disable broadcasting. |
channelName (optional) | string | Name of the BroadcastChannel used by the default adapter. Default "theme-selection". |
BuildThemeCssMapOptions
Options for buildThemeCssMap.
| Member | Type | Description |
|---|---|---|
prefix (optional) | string | CSS custom property prefix applied to every emitted variable. |
CatalogBrand
The brand provenance for a catalog entry.
Three separate things, kept separate on purpose:
- Identity — the published reference colours and where they came from.
- Interpretation — the anchors Themvora pinned, and the roles it derived.
- Normalization — anchors the solver had to move to keep the theme readable.
| Member | Type | Description |
|---|---|---|
anchors | Record<PresetMode, readonly ResolvedAnchor[]> | Anchors pinned, per mode. |
normalized | Record<PresetMode, readonly NormalizedAnchor[]> | Anchors the solver moved, per mode. Empty when the anchor survived exactly. |
source | BrandSource | The reference material behind the preset. |
CodeTokens
Semantic colors for code and syntax surfaces.
Use this group when the application renders syntax-highlighted code, terminals, editors, or documentation code blocks.
This token group is opt-in. Themes that do not define code do not emit
--theme-code-* CSS variables.
See also: ThemeTokens
| Member | Type | Description |
|---|---|---|
attribute (optional) | string | Attribute color (markup). |
background (optional) | string | Code surface background. |
border (optional) | string | Border or divider color around code surfaces. |
comment (optional) | string | Comment / documentation text color. |
foreground (optional) | string | Default code text color. |
function (optional) | string | Function / method name color. |
gutter (optional) | string | Gutter background. |
highlight (optional) | string | Highlighted line / token background. |
keyword (optional) | string | Language keyword color. |
lineNumber (optional) | string | Line number gutter text color. |
number (optional) | string | Numeric literal color. |
operator (optional) | string | Operator color. |
property (optional) | string | Object property color. |
punctuation (optional) | string | Punctuation color. |
selection (optional) | string | Text selection highlight. |
string (optional) | string | String literal color. |
tag (optional) | string | Tag name color (markup). |
type (optional) | string | Type / class name color. |
variable (optional) | string | Variable identifier color. |
ContextRestriction
A use the system explicitly does not promise, and what to do instead.
This is the half that makes the contract useful. Knowing that primary is
not supported as body text is what turns "the brand colour looks weak on this
page" into a decision with an obvious answer.
| Member | Type | Description |
|---|---|---|
against | CoreColor | The role it must not be used against. |
instead | string | What to reach for instead. |
intended | string | What the role is for. |
role | CoreColor | The role that must not be used this way. |
ContextResult
The outcome of evaluating one context against a theme.
| Member | Type | Description |
|---|---|---|
context | SemanticContext | The context that was evaluated. |
floor | number | null | The floor it was held to, or null for a decorative context. |
passes | boolean | Whether it met its floor. Decorative contexts are always true here. |
ratio | number | null | The measured ratio, or null when a role is missing. |
ContrastCheck
The result of a single foreground/background contrast check.
| Member | Type | Description |
|---|---|---|
background | string | The resolved background color. |
backgroundToken | string | The background token name checked. |
foreground | string | The resolved foreground color. |
foregroundToken | string | The foreground token name checked. |
passesAAALarge | boolean | Whether the pair meets WCAG AAA for large text (ratio ≥ 4.5). |
passesAAANormal | boolean | Whether the pair meets WCAG AAA for normal text (ratio ≥ 7.0). |
passesAALarge | boolean | Whether the pair meets WCAG AA for large text (ratio ≥ 3.0). |
passesAANormal | boolean | Whether the pair meets WCAG AA for normal text (ratio ≥ 4.5). |
ratio | number | The WCAG contrast ratio (1 to 21). |
ContrastValidationResult
The outcome of validating a theme's color contrast.
| Member | Type | Description |
|---|---|---|
checks | ContrastCheck[] | The per-pair contrast checks performed. |
nonTextChecks | NonTextCheck[] | Non-text UI component contrast checks (WCAG 2.1 §1.4.11, 3:1). |
passCount | number | Number of text pairs passing AA normal. |
totalCount | number | Total number of text pairs checked. |
valid | boolean | true when every checked pair passes WCAG AA for normal text. |
worstRatio | number | The worst text-pair ratio found. |
CreateDiagnosticInput
Input accepted by createDiagnostic.
code, level and message are required; everything else is optional so a
diagnostic carries only what it knows.
| Member | Type | Description |
|---|---|---|
cause (optional) | unknown | The underlying error, when this reports a failure. |
code | ThemeDiagnosticCode | Stable identifier for this diagnostic. |
context (optional) | ThemeDiagnosticContext | Structured context, when available. |
hint (optional) | string | What to do instead. |
level | ThemeDiagnosticLevel | Severity, chosen deliberately rather than defaulted. |
message | string | Concise, actionable description of what is wrong. |
CSSVariablesOptions
Options for createCSSVariablesBinding.
The binding keeps CSS custom properties (--theme-*) on a target element
(default <html>) in sync with the store, applying the current theme
immediately on creation and diffing subsequent updates. It can write
variables inline on the target or into a single <style> element wrapped
in a cascade layer.
| Member | Type | Description |
|---|---|---|
layerName (optional) | string | Cascade layer name used when styleSheet is enabled. |
onBeforeSwap (optional) | __type(theme: ThemeDefinition, emitOptions?: { suppressTransition?: boolean }): void | Applied inside the single View Transition lightswitch right before the CSS variables are swapped, so the old snapshot shows the old attributes AND old colors together. Lets a co-binding (e.g. the DOM binding's apply) stay in sync with the crossfade instead of starting its own View Transition (which would skip/abort the first one). |
prefix (optional) | string | Prefix for the emitted custom properties. |
styleSheet (optional) | boolean | When true, write variables into a <style> element (in a cascade layer) instead of inline on the target. |
target (optional) | HTMLElement | Element to write the CSS variables onto. |
transition (optional) | ThemeTransitionOptions | Transition applied when the theme changes. When omitted, the default theme transition is used. |
DebuggerPluginOptions
Options for createDebuggerPlugin.
| Member | Type | Description |
|---|---|---|
label (optional) | string | Prefix used for all debug log output. Default "[themvora:debug]". |
logHistory (optional) | boolean | Log history events. Default false. |
logPersistence (optional) | boolean | Log theme selection persistence events. Default true. |
logThemeChanges (optional) | boolean | Log theme changes to the console. Default true. |
logTokenUpdates (optional) | boolean | Log active theme tokens after a theme change. Default true. |
DevToolsPluginOptions
Options for createDevToolsPlugin.
| Member | Type | Description |
|---|---|---|
enabled (optional) | boolean | Whether the plugin exposes runtime state to the browser devtools. Default true. |
DOMBindingOptions
Options for createDOMBinding.
The binding syncs the store theme to the DOM — data-theme,
data-theme-mode, data-theme-family, the dark class and the
color-scheme style — with optional transition support. It requires a
target element; when none is available the binding is not created.
| Member | Type | Description |
|---|---|---|
attributeName (optional) | string | Attribute name used to expose the theme name. |
selection (optional) | DOMSelectionSource | null | Mirrors the visitor's selection onto data-theme-selection-mode and data-theme-selection-family. When omitted, neither attribute is written. |
subscribe (optional) | boolean | Subscribe to the store on its own. Default true; disable when the owner (e.g. the CSS-variables binding) drives DOM updates through its transition pipeline instead. |
target (optional) | HTMLElement | Element to apply the theme attributes/classes to. |
transition (optional) | ThemeTransitionOptions | Transition applied when the theme changes. When omitted, changes are applied instantly. |
EffectiveConfiguration<T extends ThemeDefinition>
The outcome of resolving a configuration change: the effective selection and the theme it resolves to.
| Member | Type | Description |
|---|---|---|
selection | ThemeSelectionState | The effective selection after the configuration change. |
theme | T | The theme the effective selection resolves to. |
EmitDiagnosticOptions
Options for emitDiagnostic.
| Member | Type | Description |
|---|---|---|
dedupe (optional) | boolean | Whether to suppress a diagnostic already emitted with the same code and context. Default true. Reactive paths call the same API on every render or every store update, so without this a single mistake floods the console. The first occurrence is the informative one. |
dev (optional) | boolean | Override environment detection. |
sink (optional) | DiagnosticSink | Where to write. Defaults to the matching console method for the level. |
GeneratedThemeLookup<T extends ThemeDefinition>
The result of looking up the generated theme among registered themes.
| Member | Type | Description |
|---|---|---|
candidates | readonly T[] | Every registered generated theme, in registration order. For diagnostics. |
status | GeneratedThemeStatus | Which case was hit. |
theme | T | null | The resolved generated theme, or null when none could be resolved. |
GeneratedThemePair
The light and dark themes produced by generateTheme.
| Member | Type | Description |
|---|---|---|
dark | ThemeDefinition | The generated dark theme. |
light | ThemeDefinition | The generated light theme. |
GenerateThemeOptions
Options for generateTheme.
| Member | Type | Description |
|---|---|---|
algorithm (optional) | string | Generation algorithm to use. Omitted means the current algorithm. Present so a caller can pin a shipped theme to the algorithm that produced it. |
contrast (optional) | "AA" | Contrast level to solve for. Only "AA" is implemented; it is also the default, so omitting this changes nothing. The type deliberately admits no other value rather than accepting one and quietly ignoring it. |
family (optional) | string | Theme family name used for the generated themes' meta.family and names. |
seed | string | Hex color seed (e.g. "#d97706") that drives the generated palette. |
style (optional) | GenerationStyle | Visual language to generate in. Omitted means "balanced", which is the behavior existing callers already get. |
withCode (optional) | boolean | Also generate a tokens.code block (syntax-highlighting colors) alongside the color tokens. Opt-in — most themes don't need code tokens. |
GenerationPluginOptions
Options for createGenerationPlugin.
| Member | Type | Description |
|---|---|---|
onGenerate (optional) | __type(options: GenerateThemeOptions): void | Called with the resolved options each time a theme is generated. |
options (optional) | Omit<GenerateThemeOptions, "seed"> | Default generation options, merged under any per-call overrides. |
seed (optional) | string | Default seed used by GenerationPlugin.generate when none is passed. |
HistoryEntry<T extends ThemeDefinition>
A single recorded theme state.
| Member | Type | Description |
|---|---|---|
theme | T | The theme state at this point in history. |
timestamp | number | Epoch-milliseconds timestamp of when the entry was recorded. |
HistoryPluginOptions
Options for createHistoryPlugin.
| Member | Type | Description |
|---|---|---|
maxSteps (optional) | number | Maximum number of theme selections retained in history. Default 50. |
InitialThemeResolution<T extends ThemeDefinition>
The result of initial theme resolution: the resolved theme plus the resolved selection state.
| Member | Type | Description |
|---|---|---|
selection | ThemeSelectionState | The resolved selection (family + mode). |
theme | T | The theme to activate. |
InvalidOption
A single unusable option inside a live configuration update.
Used by the runtime's configure() validation so the diagnostic names the
exact option and value rather than reporting the whole update as invalid.
| Member | Type | Description |
|---|---|---|
expected | string | A short description of what would have been accepted. |
property | string | Dotted option path, e.g. "transition.duration". |
received | unknown | The value that was supplied. |
LevelIssue
A problem found at a specific level.
| Member | Type | Description |
|---|---|---|
code | ThemeDiagnosticCode | Stable diagnostic code. |
context (optional) | ThemeDiagnosticContext | Structured context. |
level | ValidationLevel | Which level found it. |
message | string | Human-readable description. |
path (optional) | string | Dot-path to the offending token, when there is one. |
MeasuredPair
One measured contract pair.
| Member | Type | Description |
|---|---|---|
background | string | The background role. |
readonly direction (optional) | ContrastFailureDirection | Which token is too light/dark, when the pair fails. Absent when the pair passes. |
floor | number | The published floor for this requirement. |
foreground | string | The foreground role. |
passes | boolean | Whether the floor is met. |
ratio | number | The measured WCAG ratio. |
requirement | "text" | "ui" | Which contract threshold applies. |
readonly severity (optional) | ContrastSeverity | How far below the floor, when the pair fails. Absent when the pair passes. |
MigrateOptions
Options for migrateTheme.
| Member | Type | Description |
|---|---|---|
targetVersion (optional) | string | The version to migrate the theme to. |
MigrationStep
A single step in the theme migration chain, moving themes from one version to the next.
| Member | Type | Description |
|---|---|---|
description | string | Human-readable description of what the step changes. |
from | string | The version this step migrates from. |
migrate (optional) | __type(theme: ThemeDefinition): ThemeDefinition | Optional custom transformation applied to the theme. |
remapColors (optional) | TokenRemap[] | Optional color token renames applied to tokens.colors. |
to | string | The version this step migrates to. |
ModuleOptions
Configuration options for the @themvora/nuxt module, set under the
themvora key in nuxt.config.ts. The module installs an app-wide theme
runtime, registers the theme components and composables, and wires the
SSR-first cookie contract so the browser paints already themed.
See also: ResolveThemeFromCookiesOptions, NuxtThemeBootstrapOptions
| Member | Type | Description |
|---|---|---|
defaultTheme (optional) | string | Fallback theme name when no selection is persisted. |
initialFamily (optional) | string | Initial theme family when no selection is persisted. |
initialMode (optional) | ThemeMode | Initial mode: "light", "dark" or "system". Default "system". |
scheduled (optional) | false | ThemeScheduleOptions<ThemeDefinition<string>> | Sunrise/sunset scheduling. Pass { lightTheme, darkTheme, latitude, longitude, ... } to auto-switch between a light and a dark theme at sunrise/sunset. false (default) disables scheduling. Use useThemeSchedule() to read enabled/status/sunrise/sunset and to enable or disable the schedule reactively. |
scrollbar (optional) | boolean | PrePaintScrollbarOptions | Custom scrollbar bootstrap. true (or options) emits the pre-paint CSS and the tv-scrollbar class on <html> so the native scrollbar is hidden from first paint; mount <ThemeScrollbar /> to create the overlay engine (shared with every framework). |
storageKey (optional) | string | localStorage key holding the persisted selection. Default "theme-selection". |
themeOverride (optional) | ThemeOverride<string> | An explicit theme override applied over any persisted selection. Applied once per value and never written to the theme cookies. Because it is a module option it is fixed for the app rather than per page; use runtime.configure({ themeOverride }) from a plugin when it has to change at runtime. |
themes (optional) | ThemeDefinition<string>[] | Theme registry. Defaults to the built-in themes when omitted. |
transition (optional) | boolean | ThemeTransitionOptions | Theme transitions. false disables them; true (or an options object) enables smooth cross-fades on theme changes through the shared @themvora/core transition engine. |
export default defineNuxtConfig({
themvora: {
defaultTheme: "light",
initialMode: "system",
scrollbar: true,
},
});MultiWindowSyncOptions
Options for createMultiWindowSync.
Controls which cross-tab synchronization strategy is preferred and how fallbacks are reported.
| Member | Type | Description |
|---|---|---|
channelName (optional) | string | Name of the BroadcastChannel used when the broadcast strategy is selected. |
onFallback (optional) | __type(strategy: string): void | Called with a description whenever a preferred strategy is unavailable and the sync falls back to the next one. |
prefer (optional) | "broadcast" | "sharedworker" | "auto" | Preferred strategy. "auto" tries broadcast first, then shared worker. |
NonTextCheck
The result of a single non-text UI component contrast check (WCAG 2.1 §1.4.11).
| Member | Type | Description |
|---|---|---|
background | string | — |
backgroundToken | string | — |
foreground | string | — |
foregroundToken | string | — |
passesNonText | boolean | — |
ratio | number | — |
NormalizedAnchor
An anchor the solver had to move, rendered as hex.
| Member | Type | Description |
|---|---|---|
anchor | string | The exact value the brand published. |
label | string | What the brand calls it. |
resolved | string | The value the theme actually ships. |
role | string | The Themvora role. |
NuxtThemeBootstrapOptions<T extends ThemeDefinition>
Options for createNuxtThemeBootstrapScript. Describes the theme registry and the fallback selection used to build the blocking bootstrap script and its default light/dark CSS maps.
See also: createNuxtThemeBootstrapScript, resolveThemeFromCookies
| Member | Type | Description |
|---|---|---|
defaultTheme (optional) | T["name"] | Fallback theme name when no selection is persisted. |
initialFamily (optional) | string | Initial theme family used when no valid family cookie is present. |
initialMode (optional) | ThemeMode | Fallback mode when no valid mode cookie is present. Defaults to the fallback theme's own mode — the mode defaultTheme resolves to, so "light" for mint-light and "dark" for mint-dark. Pass "system" to follow prefers-color-scheme instead. |
themes | readonly T[] | The theme registry the bootstrap resolves against. |
OverlayScrollbarHandle
Runtime handle to a live overlay scrollbar instance.
Returned by the scrollbar factory, this handle lets callers force a re-synchronization of layout and physics, or tear down the scrollbar and release all of its DOM, observers, and listeners.
| Member | Type | Description |
|---|---|---|
destroy | void | — |
update | void | — |
destroy is idempotent: calling it more than once is safe and has no
further effect.
OverlayScrollbarOptions
Configuration for the overlay scrollbar engine.
All properties are optional; the engine applies sensible defaults for any omitted value. The browser always performs the actual scrolling — this engine only renders a theme-aware, animated overlay that represents the scrollbar and synchronizes with native scrolling.
| Member | Type | Description |
|---|---|---|
activeThumbColor (optional) | string | Custom thumb color while the user is dragging it. When set, overrides the theme-derived active color. Default undefined (uses thumbColor or theme-derived). |
animationDuration (optional) | number | rAF easing time constant (ms) for smooth thumb travel. Default 180. |
arrowDownIcon (optional) | ArrowIcon | Content for the "scroll down" button. Falls back to arrowIcon. Trusted markup only — see arrowIcon. |
arrowIcon (optional) | ArrowIcon | Optional content shown inside every arrow button (overrides the built-in CSS triangle). Accepts an innerHTML string, a DOM node (element / inline SVG / text) or an array of both. Trusted markup only. A string is inserted as HTML, so it must be markup you control — never user-controlled content. See ArrowIcon. |
arrowIconRenderer (optional) | __type(button: HTMLDivElement, dir: ScrollbarArrowDir): void | Framework hook: invoked for every arrow button that has custom content, so framework wrappers (React/Vue/Svelte/...) can render framework-owned elements (JSX/VNodes/...) into the button. When set it replaces the innerHTML/node injection for arrowIcon-style options. |
arrowLeftIcon (optional) | ArrowIcon | Content for the "scroll left" button. Falls back to arrowIcon. Trusted markup only — see arrowIcon. |
arrowRightIcon (optional) | ArrowIcon | Content for the "scroll right" button. Falls back to arrowIcon. Trusted markup only — see arrowIcon. |
arrows (optional) | boolean | Show the up/down (or left/right) navigation buttons like native browser scrollbars. Clicking scrolls a step; holding repeats. Default true. |
arrowUpIcon (optional) | ArrowIcon | Content for the "scroll up" button. Falls back to arrowIcon. Trusted markup only — see arrowIcon. |
autoHide (optional) | boolean | Fade the thumb/track out while idle. Default true (macOS-style). |
autoHideDelay (optional) | number | Idle (ms) before a revealed strip fades out after its last activity. Each host has its own timer, so only the strip you're scrolling/hovering is revealed, then it fades after idle; other scrollbars stay hidden. Default 900. Only takes effect when autoHide is true. |
axes (optional) | ScrollbarAxis[] | Which axes to render. Defaults to both. |
clickToJump (optional) | boolean | Clicking the empty track scrolls smoothly to that position. Default true. |
dir (optional) | "auto" | "ltr" | "rtl" | Text direction. Defaults to the resolved dir / CSS direction. |
draggable (optional) | boolean | Allow dragging the thumb to scroll. Default true. |
duration (optional) | number | CSS transition duration (ms) for thickness/opacity/color. Default 250. |
exclude (optional) | string[] | null | Skip these CSS selectors when tracking inner scrollables. |
hoverExpand (optional) | boolean | Grow the strip on hover / drag. Default false (thickness stays constant so the scrollbar never shifts while scrolling). |
hoverThickness (optional) | number | Thumb thickness while hovered / dragged — only used when hoverExpand is true. Default thickness + 4. |
iconSize (optional) | number | Arrow glyph size in CSS px, for all four directions (the built-in CSS triangle and custom icons alike). Clamped to the button's usable area, so it can never overflow an unusually thin rail. Omitted keeps the existing default sizing. Adapters surface this as icons.size. |
include (optional) | string[] | null | Scope overlay to these CSS selectors for inner scrollables (the window is always tracked). When empty, all scrollable elements are tracked. |
minThumbSize (optional) | number | Minimum thumb travel size. Default 32. |
offset (optional) | ScrollbarOffset | Distance from the container edges to the rail. A number insets every side equally; an object sets individual sides, with omitted sides defaulting to the component default (4, except left, which defaults to 0). A side set to 0 gets no inset — the rail sits flush against that edge, like a native scrollbar. The rail follows the writing direction (a vertical rail sits on the inline-end edge), so in RTL it uses left. The content is kept clear of the rail by the native scrollbar gutter the component reserves, not by extra padding, so no content width is taken and nothing reflows. |
overscroll (optional) | boolean | Subtly compress the thumb at the scroll boundaries (rubber-band feel). Default true. |
radius (optional) | number | Thumb corner radius in px. Default 999. |
smooth (optional) | boolean | Use rAF-lerped (eased) thumb motion instead of a hard snap. Default true. |
thickness (optional) | number | Resting thumb thickness (width for vertical, height for horizontal). Default 8. |
thumbColor (optional) | string | Custom thumb color (any CSS color string). When set, overrides the theme-derived color. Default undefined (theme-derived). |
thumbHoverColor (optional) | string | Custom thumb color while hovered. When set, overrides the theme-derived hover color. Default undefined (uses thumbColor or theme-derived). |
thumbOpacity (optional) | number | Thumb opacity while visible. Default 0.7. |
touch (optional) | boolean | Native (touch) devices: keep native scrollbars by default. Pass true to force the overlay on coarse-pointer devices. Default false. |
trackColor (optional) | string | Custom track color (any CSS color string). When set, overrides the theme-derived color. Default undefined (theme-derived). |
trackOpacity (optional) | number | Track strip opacity (0 = invisible). Default 0.25. |
zIndex (optional) | number | Z-index for the overlay strips. Defaults to the tracked container's own z-index (so the scrollbar stays inside its container's stacking order — e.g. a rail inside a sticky header never floats above that header). Containers that declare no z-index get 0; the document scrollbar gets 55, which is above typical sticky headers (50) and below full-screen modal backdrops (60) — the window bar is chrome, so a fixed header must not hide it. Overriding lets you force scrollbars above fixed headers/modals if you need to. |
Options are resolved once when the scrollbar is created. include/exclude
scope which inner scrollables are tracked; the window is always tracked.
ParsedThemeJson
A parsed theme document.
| Member | Type | Description |
|---|---|---|
readonly source | string | The input with comments and trailing commas blanked out. Same length as the input, so an offset into this string is an offset into the original. Consumers that need positions scan this rather than re-parsing. |
readonly value | unknown | The parsed value. |
PersistencePluginOptions
Options for createPersistencePlugin.
| Member | Type | Description |
|---|---|---|
adapter (optional) | ThemeSelectionPersistenceAdapter | null | Custom persistence adapter. When omitted, a localStorage-backed adapter is used in browser environments; in non-browser (SSR) environments the plugin is inert. Pass null to disable persistence entirely. |
key (optional) | string | Storage key used by the default localStorage adapter. Default "theme-selection". |
readOnInit (optional) | boolean | Whether to restore the saved theme selection when the runtime is created. Default true. |
PluginManager<T extends ThemeDefinition>
Registry that manages the lifecycle of ThemePlugin instances.
The manager stores plugins by name, orders them by priority for hook dispatch, and coordinates creation and destruction. It is created by createPluginManager.
| Member | Type | Description |
|---|---|---|
destroy | void | — |
get | ThemePlugin<T> | undefined | — |
list | ThemePlugin<T>[] | — |
remove | boolean | — |
use | __type(): void | — |
use is idempotent per name: registering an already-registered name is
skipped with a warning. destroy invokes onDestroy for every plugin and
clears the registry; after destruction the manager is empty.
PresetCatalogEntry
Everything a preset page needs about one preset family.
| Member | Type | Description |
|---|---|---|
algorithm | string | The algorithm that produced it. |
brand (optional) | CatalogBrand | Brand reference provenance. Present on brand entries only. |
brandColor (optional) | string | The official brand colour, for documentation. Brand recipes only. |
character | string | The recipe's one-line character descriptor. |
family | string | Theme family, e.g. "oat". |
id | string | Stable identifier, e.g. "oat". |
kind | PresetKind | Curated default, or brand-inspired. |
modes | readonly PresetMode[] | Which modes this family ships. |
name | string | Display name, e.g. "Oat". |
provenance (optional) | BrandProvenance | How faithful a brand recipe is. Present on brand recipes only. |
quality | PresetQuality | The merged quality summary. |
radius | string | Border radius. |
seed | string | The seed the palette is generated from. |
style | GenerationStyle | The generation style. |
tags | readonly string[] | Free-form recipe tags. |
temperature | Temperature | Derived from the seed's identity. |
themes | Record<PresetMode, ThemeDefinition> | The resolved themes. |
PresetCheck
One row of the scorecard.
| Member | Type | Description |
|---|---|---|
detail (optional) | string | Why it failed, when it did. |
id | string | Stable identifier, e.g. "text-contrast". |
label | string | Human-readable label. |
status | CheckStatus | The outcome. |
PresetQuality
The quality summary for a preset, merged across both modes.
A check passes only if it passes in both light and dark. This is the same
result scripts/audit-presets.mjs gates on — the page consumes the quality
model rather than running a second contrast implementation.
| Member | Type | Description |
|---|---|---|
checks | readonly PresetCheck[] | Per-check detail, merged across modes. |
failures | readonly string[] | Check ids that failed in at least one mode. |
passed | number | Checks that did not fail, across both modes. |
total | number | Total checks. |
warnings | readonly string[] | Check ids that warned in at least one mode. |
PresetScore
The scorecard for one theme.
| Member | Type | Description |
|---|---|---|
checks | PresetCheck[] | Every check, in order. |
family | string | null | Theme family. |
mode | string | null | Theme mode. |
name | string | Theme name. |
passed | number | How many checks passed. |
total | number | How many checks there are. |
PresetVariantOverride
Token overrides applied to a single preset theme mode.
| Member | Type | Description |
|---|---|---|
tokens (optional) | Partial<ThemeTokens> | Partial token groups merged over the preset's base tokens. |
ProvidedThemeFamily<T extends ThemeDefinition>
A discoverable theme family: every variant the provider was given for one canonical family, in the order they were supplied.
See also: normalizeProvidedThemes, createProvidedThemesSource
| Member | Type | Description |
|---|---|---|
family | string | The canonical family identifier used for selection. |
id | string | Stable identifier for this family. Derived from the canonical family identity (meta.family, or "default"), so it survives a change of display label and is unique within one provider. |
meta (optional) | ThemeMeta | Roll-up of the family's metadata, taken from its first variant that carries any. Per-variant values live on ProvidedThemeVariant.meta. |
name | string | Display name for the family: the first variant's meta.label, else the family identifier. |
provenance (optional) | ProvidedThemeProvenance | Provenance declared by the family's first variant that declares one. Absent when nothing in the input declares provenance — the API never guesses a source from a name. |
variants | readonly ProvidedThemeVariant<T>[] | The family's variants, in supplied order. Never empty. |
const themes = useProvidedThemes();
return themes.map((family) => (
<fieldset key={family.id}>
<legend>{family.name}</legend>
{family.variants.map((variant) => (
<button key={variant.name} onClick={() => setTheme(variant.name)}>
{variant.mode}
</button>
))}
</fieldset>
));ProvidedThemesSource<T extends ThemeDefinition>
A reactive source of the themes a provider was given.
See also: createProvidedThemesSource
| Member | Type | Description |
|---|---|---|
get | readonly ProvidedThemeFamily<T>[] | — |
subscribe | __type(): void | — |
ProvidedThemeVariant<T extends ThemeDefinition>
One variant of a theme family: a single registered theme definition.
See also: ProvidedThemeFamily
| Member | Type | Description |
|---|---|---|
meta (optional) | ThemeMeta | The metadata supplied with this variant, exactly as the provider holds it. This is the authoritative per-variant metadata; the family-level meta is a documented roll-up of it. |
mode | ThemeMode | The variant's resolved colour mode. |
name | string | The theme's registered name, e.g. "mint-dark". |
theme | T | The definition the provider holds for this variant. Reading a field the grouped view does not model (a custom extends, an application-specific extension) is always possible from here. |
tokens | ThemeTokens | The variant's semantic tokens, resolved. Token references, auto() / contrast() calls and expressions are already evaluated, so a consumer can read a value directly (tokens.colors?.primary) without re-running the resolver. |
RegistryLoadFailure
A registry that could not be read, and why.
| Member | Type | Description |
|---|---|---|
readonly location (optional) | RegistrySourceLocation | Where in the source, when a position is known. |
readonly message | string | A sentence naming what was wrong and where. |
readonly ok | false | Discriminant. |
readonly reason | RegistryFailureReason | Category, for callers that branch. |
RegistryLoadSuccess
A registry that was read.
| Member | Type | Description |
|---|---|---|
readonly defaultTheme (optional) | string | The theme the application opens with, when the module records one. |
readonly ok | true | Discriminant. |
readonly origins | readonly ThemeDefinitionOrigin[] | The provenance of each theme, aligned with themes. A generated registry combines its own definitions with the preset families in selection, so the combined list alone cannot tell a project's theme from a curated preset. This does. |
readonly selection | readonly string[] | The families the module selects. |
readonly themes | readonly ThemeDefinition<string>[] | Every theme the module registers, in the module's own order. |
RegistrySourceLocation
A position in the source, 1-based, for an error message.
| Member | Type | Description |
|---|---|---|
readonly column | number | Column number, 1-based. |
readonly line | number | Line number, 1-based. |
ResolvedSolarLocation
The resolved coordinates a solar calculation should use, plus how they were derived.
| Member | Type | Description |
|---|---|---|
autoDetected | boolean | Whether the coordinates came from timezone resolution (explicit timeZone or browser auto-detection) rather than explicit coordinates. |
latitude | number | The resolved latitude. |
longitude | number | The resolved longitude. |
timeZone | string | null | The timezone the coordinates were resolved from, or null when explicit coordinates were used (or nothing could be detected). |
ResolvedThemeReference<T extends ThemeDefinition>
A theme reference that resolved against a provider's catalog.
See also: resolveThemeReference
| Member | Type | Description |
|---|---|---|
family | string | The canonical family the reference belongs to. |
kind | "variant" | "family" | Which naming form was used. "variant" means the reference named one definition exactly; "family" means it named a group and the variant was chosen by the mode contract. |
mode (optional) | ThemeMode | The variant's own mode. Present only for a "variant" reference: that is the only case where the reference itself states a mode. A family reference deliberately leaves this undefined so the caller's mode contract decides. |
theme | T | The definition the reference resolves to. |
ResolveInitialThemeOptions<T extends ThemeDefinition>
Options for resolving the initial theme of a runtime.
| Member | Type | Description |
|---|---|---|
defaultTheme (optional) | ThemeIdentifier<T> | Theme to prefer when no family/mode selection is given (variant or family). |
family (optional) | string | Initial family. Defaults to the fallback theme's family. |
mode (optional) | ThemeMode | Initial mode. "system" is resolved via prefersDark. |
prefersDark (optional) | boolean | Whether the visitor prefers dark mode. Used only when mode is "system". |
themes | readonly T[] | Registered themes to resolve within. |
ResolveSelectionOptions<T extends ThemeDefinition>
Options for resolving a selection state.
| Member | Type | Description |
|---|---|---|
defaultTheme (optional) | string | Fallback theme: a variant name ("mint-dark") or a family name ("mint"). See resolveThemeReference. |
initialFamily (optional) | string | Initial family. A variant name is accepted too and normalised to its family — its mode is then used only when initialMode is not supplied. |
initialMode (optional) | ThemeMode | Initial mode. Defaults to the fallback theme's mode. |
persistedSelection (optional) | ThemeSelectionState | null | A persisted selection that wins over the other inputs when present. |
themes | readonly T[] | Registered themes to resolve within. |
ResolveSelectionThemeOptions<T extends ThemeDefinition>
Options for resolving the theme for an existing selection.
| Member | Type | Description |
|---|---|---|
prefersDark (optional) | boolean | Whether the visitor prefers dark mode. Used only when the selection mode is "system". |
selection | ThemeSelectionState | The selection (family + mode) to resolve a theme for. |
themes | readonly T[] | Registered themes to resolve within. |
ResolveThemeFromCookiesOptions<T extends ThemeDefinition>
Options for resolveThemeFromCookies. Describes the theme registry, the fallback selection, and the parsed request cookies used to resolve the initial theme server-side.
See also: resolveThemeFromCookies
| Member | Type | Description |
|---|---|---|
cookies | ParsedCookies | The parsed request cookies (see parseCookieHeader). |
defaultTheme (optional) | T["name"] | Fallback theme name when no selection is persisted. |
initialFamily (optional) | string | Initial theme family used when no valid family cookie is present. |
initialMode (optional) | ThemeMode | Fallback mode when no valid mode cookie is present. Defaults to the fallback theme's own mode — the mode defaultTheme resolves to, so "light" for mint-light and "dark" for mint-dark. Pass "system" to follow prefers-color-scheme instead. |
themes | readonly T[] | The theme registry the selection is resolved against. |
ResolveThemeReferenceOptions
Options for resolveThemeReference.
| Member | Type | Description |
|---|---|---|
mode (optional) | ThemeMode | Mode used to pick a variant when the reference names a family. |
prefersDark (optional) | boolean | Whether the visitor prefers dark. Used only when mode is "system". |
ScheduledPluginOptions<T extends ThemeDefinition>
Options for createScheduledPlugin.
| Member | Type | Description |
|---|---|---|
autoDetectLocation (optional) | boolean | Auto-detect the visitor's location from their browser timezone when no explicit coordinates/timezone are given. Default true. |
checkInterval (optional) | number | How often (ms) the schedule re-evaluates the current time. |
darkTheme (optional) | T["name"] | Theme applied between sunset and sunrise. Optional — same derivation as lightTheme, falling back to the built-in neutral "dark" theme. |
enabled (optional) | boolean | Start enabled. Default true. |
latitude (optional) | number | Explicit coordinates. Optional — when omitted the location is resolved from timeZone or the visitor's browser timezone. |
lightTheme (optional) | T["name"] | Theme applied between sunrise and sunset. Optional — when omitted the schedule derives it from the currently selected theme's family (or falls back to the built-in neutral "light" theme). |
longitude (optional) | number | Explicit longitude. Optional — when omitted the location is resolved from timeZone or the visitor's browser timezone. |
skipApplyMs (optional) | number | Minimum time (ms) between automatic theme applications, used to avoid rapid re-application near a boundary. |
timeZone (optional) | string | IANA timezone to resolve coordinates from when latitude/longitude are omitted (e.g. "Asia/Kathmandu"). |
ScheduledThemeBindingOptions<T>
Options for createScheduledThemeBinding.
The binding applies a light theme during daytime and a dark theme at night, based on sunrise/sunset at a resolved location, re-checking on an interval.
| Member | Type | Description |
|---|---|---|
autoDetectLocation (optional) | boolean | Auto-detect the visitor's location from their browser timezone when no explicit coordinates/timezone are given. Default true. |
checkInterval (optional) | number | How often (ms) the binding re-checks solar time. |
darkTheme | T | Theme applied between sunset and sunrise. |
enabled (optional) | boolean | Whether the binding should apply themes and run its timer. Defaults to true. Toggle at runtime via the returned setEnabled. |
getTimes (optional) | __type(date: Date, latitude: number, longitude: number): SunTimes | Override the sunrise/sunset computation. Defaults to calculateSunTimes. A custom implementation may omit polar; the binding then falls back to the sunrise <= now < sunset interval. |
latitude (optional) | number | Explicit latitude. Optional — when omitted the binding resolves the location from timeZone or the visitor's browser timezone. |
lightTheme | T | Theme applied between sunrise and sunset. |
longitude (optional) | number | Explicit longitude. Optional — see latitude. |
onBeforeApply (optional) | __type(theme: T): boolean | Called before the binding applies a theme. Return false to block the switch for this cycle. |
skipApplyMs (optional) | number | Ignore schedule-driven applies within this many ms after a manual selection (e.g. a cross-tab sync). |
timeZone (optional) | string | IANA timezone to resolve coordinates from when latitude/longitude are omitted (e.g. "Asia/Kathmandu"). |
ScheduledThemeOptions<T extends ThemeDefinition>
Configures the runtime's automatic sunrise/sunset scheduling.
When provided, the runtime creates a schedule controller that applies the light or dark theme of the selected family based on solar times.
| Member | Type | Description |
|---|---|---|
autoDetectLocation (optional) | boolean | Auto-detect the visitor's location from their browser timezone when no explicit coordinates/timezone are given. Default true. |
checkInterval (optional) | number | How often the schedule re-checks the solar state, in milliseconds. Passed through to the underlying schedule controller. |
darkTheme (optional) | T["name"] | Theme applied between sunset and sunrise. Optional — same derivation as lightTheme, falling back to the built-in neutral "dark" theme. |
enabled (optional) | boolean | Start enabled. Default true. |
getTimes (optional) | __type(date: Date, latitude: number, longitude: number): SunTimes | Override the sunrise/sunset computation. Defaults to the NOAA calculation in calculateSunTimes. Supply one to drive the schedule from a known clock — a test that must not depend on the real sun, or a product that defines "daytime" its own way. Read once when the schedule is created; a later configure({ scheduled }) keeps the original function, because changing it mid-flight would re-interpret the transition that is already pending. |
latitude (optional) | number | Explicit latitude. Optional — when omitted the location is resolved from timeZone or the visitor's browser timezone, so every user gets sunrise/sunset for their own location automatically. |
lightTheme (optional) | T["name"] | Theme applied between sunrise and sunset. Optional — when omitted the schedule derives it from the currently selected theme's family (or falls back to the built-in neutral "light" theme). |
longitude (optional) | number | Explicit longitude. Optional — see latitude. |
skipApplyMs (optional) | number | Minimum time, in milliseconds, between two applications of the same theme — remote changes inside this window are ignored. |
timeZone (optional) | string | IANA timezone to resolve coordinates from when latitude/longitude are omitted (e.g. "Asia/Kathmandu"). Takes precedence over auto-detection. |
ScheduledThemePairInput<T extends ThemeDefinition>
Input for resolving the scheduled light/dark theme pair.
Both fields are optional; when omitted the pair is derived from the
currently selected theme's family, falling back to the neutral light/dark
themes.
| Member | Type | Description |
|---|---|---|
darkTheme (optional) | T["name"] | The theme applied at night. |
lightTheme (optional) | T["name"] | The theme applied during daytime. |
ScopedThemeBindingOptions
Options for createScopedThemeBinding.
The binding applies a scoped theme's CSS variables inline on a target element and cleans them up on destroy. Local theme definitions are resolved first, then the parent runtime's themes fall back — no second runtime is ever created.
| Member | Type | Description |
|---|---|---|
localThemes (optional) | readonly ThemeDefinition<string>[] | Local theme definitions for genuinely isolated components. These are resolved FIRST, then the parent runtime's themes fall back — no second runtime is ever created. |
prefersDark (optional) | boolean | Whether the OS prefers dark (used to resolve mode: "system" and the default light fallback for family-only selections). |
prefix (optional) | string | Prefix for the emitted custom properties. |
transition (optional) | ThemeTransitionOptions | Transition applied when the scoped theme changes. When omitted, the change is applied instantly (the previous behaviour). Pass the owning runtime's transition to inherit the same transition the provider uses. |
ScopedThemePrePaint
Everything a scoped region needs to render correctly at first paint, resolved generically from its theme data.
When the scope's selection is OS-dependent, css carries a
@media (prefers-color-scheme: dark) block so the region renders light OR
dark before hydration; the live binding takes over through its own inline
variables afterwards.
| Member | Type | Description |
|---|---|---|
css | string | null | [selector] { light } + @media (prefers-color-scheme: dark) { [selector] { dark } }, or null when the scope isn't OS-dependent. Emit this into the rendered markup so the first paint already shows the correct theme. Escaped for <style>-element content: </ is written as </ (a CSS escape for /), so a token value cannot close the element. Do not pass it to style.setProperty() — it belongs in a stylesheet. |
isDark | boolean | Whether the default resolved theme is dark. |
lightVariables | Record<string, string> | The default (light) scoped variables, including the --color-* / --radius-* aliases. When systemBased, these are the SSR/fallback values and the element should NOT carry them inline (the media-query override would lose to inline styles); when not, they become the element's inline style. |
name | string | The default resolved theme name (for data-theme-style attributes). |
systemBased | boolean | True when the scope's resolved theme depends on the OS scheme (its selection is a family / boundary following a system mode, so resolving with and without prefers-color-scheme: dark picks a different theme). These scopes need the @media CSS block to render correctly at first paint — the server can't know the OS preference yet. |
ScopedThemePrePaintOptions
Options for resolveScopedThemePrePaint.
Controls how a scope's first-paint CSS is generated.
| Member | Type | Description |
|---|---|---|
prefix (optional) | string | Prefix for the emitted custom properties. |
selector (optional) | string | CSS selector targeting the scope element (e.g. [data-themvora-scope="…"]). Only used by the @media override. |
ScrollbarAppearanceOptions
The look and size of every rail.
| Member | Type | Description |
|---|---|---|
activeThumbColor (optional) | string | — |
animationDuration (optional) | number | — |
arrows (optional) | boolean | — |
duration (optional) | number | — |
hoverThickness (optional) | number | — |
iconSize (optional) | number | Arrow glyph size, in CSS px (see OverlayScrollbarOptions.iconSize). Adapters surface this as icons.size. |
minThumbSize (optional) | number | — |
offset (optional) | ScrollbarOffset | — |
radius (optional) | number | — |
thickness (optional) | number | — |
thumbColor (optional) | string | — |
thumbHoverColor (optional) | string | — |
thumbOpacity (optional) | number | — |
trackColor (optional) | string | — |
trackOpacity (optional) | number | — |
zIndex (optional) | number | — |
ScrollbarBehaviorOptions
How the overlay scrolls and hides.
| Member | Type | Description |
|---|---|---|
autoHide (optional) | boolean | — |
autoHideDelay (optional) | number | — |
axes (optional) | ScrollbarAxis[] | — |
clickToJump (optional) | boolean | — |
dir (optional) | "auto" | "ltr" | "rtl" | — |
draggable (optional) | boolean | — |
hoverExpand (optional) | boolean | — |
overscroll (optional) | boolean | — |
smooth (optional) | boolean | — |
touch (optional) | boolean | — |
ScrollbarGroupedOptions
The grouped form accepted by every adapter. Each group is optional and may
be passed explicitly as undefined, so adapters can forward their raw props
without stripping keys first.
| Member | Type | Description |
|---|---|---|
appearance (optional) | ScrollbarAppearanceOptions | — |
behavior (optional) | ScrollbarBehaviorOptions | — |
scope (optional) | ScrollbarScopeOptions | — |
ScrollbarIconOptions<T>
Arrow icon content for the icons group. arrow covers every direction;
the per-direction entries override it; size is the shared glyph size in
CSS px. T is the adapter's native icon value (an HTML/node icon for the
string-based adapters, framework nodes for React and friends).
| Member | Type | Description |
|---|---|---|
arrow (optional) | T | — |
down (optional) | T | — |
left (optional) | T | — |
right (optional) | T | — |
size (optional) | number | — |
up (optional) | T | — |
ScrollbarOffsetSides
Per-side rail offsets, in px.
Each side is the distance from that container edge to the rail. Any side left
out falls back to the component default (4). Pass a plain number instead to
inset every side equally.
| Member | Type | Description |
|---|---|---|
bottom (optional) | number | — |
left (optional) | number | — |
right (optional) | number | — |
top (optional) | number | — |
ScrollbarScopeOptions
Which containers the overlay tracks. Scope decides where the scrollbar
appears, not how it looks — so it is its own group rather than part of
appearance.
| Member | Type | Description |
|---|---|---|
exclude (optional) | string[] | null | — |
include (optional) | string[] | null | — |
SelectionThemeResolution<T extends ThemeDefinition>
The result of selection-theme resolution.
| Member | Type | Description |
|---|---|---|
selection | ThemeSelectionState | The (possibly normalized) selection. |
theme | T | The theme matching the selection. |
SemanticContext
One promise about where a role may be used.
| Member | Type | Description |
|---|---|---|
against | CoreColor | The role it is drawn on. |
description | string | What the UI is doing, in words. |
id | string | Stable id, used in diagnostics and fixtures. |
level | ContextLevel | Whether the generator guarantees it. |
owner | ContextOwner | Who has to make it true. |
requirement | ContextRequirement | The threshold it is held to. |
role | CoreColor | The role carrying the content or indicator. |
SemanticRoleGroup
How a semantic role is grouped, by what it is for rather than where it is used. The grouping is documentation and validation metadata — it is what lets a reviewer answer "is this a surface or an action?" without consulting a specific library's token list.
| Member | Type | Description |
|---|---|---|
description | string | What the group is for. |
id | "canvas" | "surfaces" | "actions" | "states" | "interaction" | Group identifier. |
label | string | Human-readable label. |
optional (optional) | readonly OptionalSemantic[] | Optional roles in this group, if any. |
roles | readonly CoreColor[] | The core roles in this group. |
SolarLocationInput
Input for resolving the coordinates a solar calculation should use.
Priority: explicit latitude/longitude → explicit timeZone → browser
timezone auto-detection → DEFAULT_TIMEZONE_LOCATION.
| Member | Type | Description |
|---|---|---|
autoDetectLocation (optional) | boolean | Auto-detect the visitor's location from their browser timezone when no explicit coordinates/timezone are given. Default true. On the server (no window) detection is skipped and the default coordinates are used so SSR output stays deterministic. |
latitude (optional) | number | Explicit latitude. When present (alone or with longitude) it wins over timezone resolution. |
longitude (optional) | number | Explicit longitude. When present (alone or with latitude) it wins over timezone resolution. |
timeZone (optional) | string | IANA timezone to resolve coordinates from (e.g. "Asia/Kathmandu"). Takes precedence over auto-detection. |
StorageAdapter
A minimal key-value contract for persisting the selected theme name.
Implementations back this with any durable store (e.g. localStorage).
get returns null when nothing has been stored yet or the stored value
is not a valid theme name.
| Member | Type | Description |
|---|---|---|
get | string | null | — |
remove | void | — |
set | void | — |
SunTimes
The sunrise/sunset pair for one calendar day at one location.
| Member | Type | Description |
|---|---|---|
polar (optional) | "day" | "night" | Set when the sun stays up ("day") or stays down ("night") for the whole day. Absent on an ordinary day, and absent from a custom getTimes implementation that does not model polar conditions. |
sunrise | Date | Sunrise, as an absolute instant. |
sunset | Date | Sunset, as an absolute instant. |
sunrise and sunset are absolute instants on the host's local clock:
the calendar day is the local day of the Date that was passed in, and the
returned instants are the correct local wall-clock times for that day,
daylight-saving transitions included. They are not solar time — see
calculateSunTimes.
polar is present only when the sun does not rise or does not set that day.
In that case sunrise/sunset still describe a usable interval — for polar
day the whole local day, for polar night a zero-length day that starts at its
end — so now >= sunrise && now < sunset is still correct. Consumers that
want to display "no sunrise today" should read polar rather than compare
the two dates.
SyncFirstRenderRoot
The shape this helper wraps: React's createRoot with a render method.
Typed structurally, and the render argument as unknown, so core carries no
React dependency — it is framework-agnostic and must stay that way.
| Member | Type | Description |
|---|---|---|
render | unknown | — |
unmount | void | — |
SyncFirstRootOptions
Options for createSyncFirstRoot.
See also: createSyncFirstRoot
| Member | Type | Description |
|---|---|---|
onlyFirstRoot (optional) | boolean | Wrap only the first root created, and pass every later one through untouched. Defaults to false. |
SystemThemeBindingOptions<T extends ThemeDefinition>
Options for createSystemThemeBinding.
The binding follows the OS color-scheme preference live and applies the
matching theme to the store. It requires a Window with a working
matchMedia; when none is available the binding is not created.
| Member | Type | Description |
|---|---|---|
applyOnCreate (optional) | boolean | Apply the current OS appearance as soon as the binding is created. |
darkTheme | T | Theme applied when the media query does not match (the OS prefers light). |
lightTheme | T | Theme applied when the media query matches (the OS prefers dark). |
mediaQuery (optional) | string | Media query used to detect the OS preference. |
view (optional) | Window | The Window to observe. Defaults to the global window when present. |
ThemeAdapter<T extends ThemeDefinition>
The contract every library adapter implements. The runtime only knows this interface — it never knows Bootstrap, MUI, Chakra or any other library.
| Member | Type | Description |
|---|---|---|
readonly id | string | Stable identifier used for reference counting and deduplication. |
readonly optional (optional) | { colors?: readonly string[] } | Roles the adapter can use but does not require. These are capabilities: warning and info are genuine semantic roles that many libraries have no slot for. An adapter lists them here and degrades gracefully when the theme omits them — by deriving a value, or by omitting the library token entirely. Never by fabricating one, which would look like support while nothing consumed it. |
readonly requires (optional) | { colors?: readonly string[]; tokens?: readonly string[] } | The semantic roles this adapter cannot function without. Declaring requirements turns a silent, per-library failure into a checkable contract. Without it, an adapter that needs primaryForeground and finds nothing simply emits a variable with an empty value, and the component renders unreadable content — which is exactly the class of defect the integration laboratory kept finding. A role listed here must resolve; an adapter may assume it is present. |
install | void | — |
supports | boolean | — |
uninstall | void | — |
ThemeAnimationInput
Input consumed by the Animation Coordinator for a single theme change.
See also: runThemeAnimation
| Member | Type | Description |
|---|---|---|
buffer (optional) | number | Extra headroom after the longest transition before cleanup. |
plan | TransitionPlan | The concrete transition decided by the planner. |
swap | __type(): void | Writes the new CSS custom-property values to target. |
target | HTMLElement | Element receiving the theme custom properties (usually <html>). |
ThemeBootstrapScriptOptions<T extends ThemeDefinition>
Options for createThemeBootstrapScript.
| Member | Type | Description |
|---|---|---|
defaultTheme (optional) | ThemeIdentifier<T> | Theme to fall back to when no persisted selection exists (variant or family). |
initialFamily (optional) | string | Initial theme family used when no persisted selection exists. |
initialMode (optional) | ThemeMode | Initial mode used when no persisted selection exists. |
prefix (optional) | string | CSS custom property prefix. Defaults to "theme-". |
storageKey (optional) | string | localStorage key holding the persisted theme selection. Defaults to "theme-selection". |
themeOverride (optional) | ThemeOverride<string> | An explicit theme override to apply before first paint, outranking any persisted selection. The blocking script runs before the runtime exists, so an override applied only by a post-mount effect would paint the saved theme first and then correct it — exactly the flash this script exists to prevent. Passing it here makes the very first frame the overridden theme. |
themes | readonly T[] | The theme definitions to embed in the generated script. |
ThemeBootstrapState<T extends ThemeDefinition>
The state the pre-paint bootstrap published on <html>, validated against
the theme registry.
See also: readBootstrapState
| Member | Type | Description |
|---|---|---|
ready | boolean | Whether the bootstrap reported completing its DOM write. |
resolvedMode | "light" | "dark" | The concrete mode the bootstrap applied ("light" or "dark"). |
selection | ThemeSelectionState | The visitor's selection. For "system" this is still "system" — the resolved mode is resolvedMode, and the two are deliberately distinct so adopting this state cannot downgrade a "system" choice. |
theme | T | The resolved theme — the one already painted on <html>. |
ThemeBroadcastAdapter
A contract for broadcasting and observing the selected theme mode across
tabs/windows. subscribe returns an unsubscribe function; destroy
releases the underlying channel.
| Member | Type | Description |
|---|---|---|
destroy | void | — |
post | void | — |
subscribe | __type(): void | — |
ThemeBroadcastOptions
Options for createThemeBroadcast.
The adapter publishes the theme mode to a BroadcastChannel and applies
incoming modes from other tabs/windows.
| Member | Type | Description |
|---|---|---|
channel (optional) | BroadcastChannelLike<ThemeMode> | A custom channel to use. When omitted, a BroadcastChannel is created from channelName. |
channelName (optional) | string | Name of the BroadcastChannel created when channel is omitted. |
ThemeChangeEvent<T extends ThemeDefinition>
A single recorded theme change, captured by a ThemeDebugger.
| Member | Type | Description |
|---|---|---|
current | T | The theme in effect after the change. |
label (optional) | string | Optional caller-supplied label describing the change. |
previous | T | null | The theme in effect before the change, or null for the first event. |
source | ThemeChangeSource | The origin of the change. |
timestamp | number | Epoch milliseconds when the change was recorded. |
ThemeConfigurationUpdate<T extends ThemeDefinition>
A live configuration change for a runtime.
This is the subset of ThemeRuntimeOptions that can change while the runtime stays mounted. Each framework adapter forwards its changed props here — the runtime owns normalization, validation, precedence and notification, so the adapters share one contract instead of each re-implementing selection.
See also: ThemeRuntime.configure
| Member | Type | Description |
|---|---|---|
defaultTheme (optional) | ThemeIdentifier<T> | Fallback theme: a variant or family identifier. |
initial (optional) | InitialThemeResolution<T> | An explicit initial resolution (SSR-resolved selection). Wins when changed. |
initialFamily (optional) | string | Initial family, used when the effective selection is re-resolved. |
initialMode (optional) | ThemeMode | Initial mode, used when the effective selection is re-resolved. |
scheduled (optional) | false | ScheduledThemeOptions<T> | Sunrise/sunset scheduling. Omit to leave the current schedule unchanged; false tears it down (runtime.schedule becomes null); an options object installs one or reconfigures the existing one in place. |
themeOverride (optional) | ThemeOverride<ThemeIdentifier<T>> | Explicit theme override. Supplied-and-semantically-different applies once; an unchanged override is never re-asserted, so it cannot fight a manual selection. Omit to leave the last applied override in place; undefined explicitly does the same (an override is not a value to revert to). |
themes (optional) | readonly T[] | The effective theme catalog. Omit to leave the current catalog unchanged. An empty or all-invalid array resolves to the canonical neutral fallback. |
transition (optional) | boolean | ThemeTransitionOptions | Transition configuration. Omit to leave the current setting unchanged; false disables transitions from the next theme change on; true or an options object enables/reconfigures them. Applied to the runtime's live DOM/CSS bindings without rebuilding them and without touching the current theme. |
ThemeCssPair
A light/dark pair, as generateTheme returns it.
Structural rather than nominal: any { light, dark } object qualifies, which
is what lets a document parsed from JSON be passed straight in.
| Member | Type | Description |
|---|---|---|
dark | ThemeDefinition | The dark theme. |
light | ThemeDefinition | The light theme. |
ThemeDebugger<T extends ThemeDefinition>
A debugger that records theme changes on a theme store.
| Member | Type | Description |
|---|---|---|
clear | void | — |
destroy | void | — |
getHistory | readonly ThemeChangeEvent<T>[] | — |
record | void | — |
ThemeDefinition<Name extends ThemeName>
A theme definition: a name plus optional metadata and token values.
See also: defineTheme, extendTheme, composeTheme
| Member | Type | Description |
|---|---|---|
extends (optional) | Name | readonly Name[] | Names of themes this definition extends. Extending merges the base themes' tokens before applying this definition's own tokens. |
meta (optional) | ThemeMeta | Metadata describing the theme family, mode, and presentation labels. |
name | Name | Stable theme identifier used for selection and lookup. |
tokens (optional) | ThemeTokens | Semantic token values consumed by the runtime. When omitted, the theme inherits tokens entirely from its extended bases. |
ThemeDefinitionProblem
A construct that looked like a definition but could not be read.
| Member | Type | Description |
|---|---|---|
readonly location | RegistrySourceLocation | Where the attempt started. |
readonly message | string | Why it could not be read. |
ThemeDefinitionReadOptions
Options for readThemeDefinitions.
| Member | Type | Description |
|---|---|---|
readonly bindings (optional) | Readonly<Record<string, string>> | Local name to canonical API name for directly imported bindings. |
readonly namespaces (optional) | Readonly<Record<string, readonly string[]>> | Local namespace to the canonical API names it may expose. |
readonly strict (optional) | boolean | When true, only the supplied bindings and namespaces are canonical. The default is false, which assumes the names as written. A project analyzer that has verified imports should set this, so a local function called getPresetThemes is not mistaken for the catalog API. |
ThemeDefinitionReadResult
What readThemeDefinitions() found.
| Member | Type | Description |
|---|---|---|
readonly definitions | readonly ThemeDefinitionSource[] | Every definition it could read. |
readonly problems | readonly ThemeDefinitionProblem[] | Every candidate it refused, so nothing is dropped silently. |
ThemeDefinitionSource
A theme definition found in source, with where it starts.
| Member | Type | Description |
|---|---|---|
readonly binding (optional) | string | The declaration the value is assigned to, when it is a simple one. export const ocean = defineTheme(…) reports ocean, and export const { light, dark } = generateTheme(…) reports light and dark respectively. Undefined when the call is not the whole initializer — a literal inside an array, a call argument, a returned value — because then no single exported name stands for it. This exists so a caller can follow the value into another module without re-parsing the declaration itself. |
readonly generateOptions (optional) | ThemeGenerationInput | The static inputs of a generateTheme() call that produced this theme. |
readonly location | RegistrySourceLocation | Where the object literal starts. |
readonly origin (optional) | ThemeDefinitionOrigin | Which canonical API produced the definition. catalog is the provenance a consumer needs to distinguish a curated preset from an application's own theme: a preset is not project-defined just because the file calls getPresetThemes(). |
readonly theme | ThemeDefinition | The definition, as defineTheme() would return it. |
readonly variant (optional) | "light" | "dark" | For a generated pair, which half of the pair this definition is. |
ThemeDiagnostic
A single Themvora diagnostic.
This is plain data: creating one has no side effects and touches no environment. Emission and formatting are separate concerns — see formatDiagnostic and emitDiagnostic — so the same diagnostic can be collected, thrown, logged, or forwarded to a DevTools layer without duplicating the logic that produced it.
See also: createDiagnostic, ThemeDiagnosticCode
| Member | Type | Description |
|---|---|---|
cause (optional) | unknown | The underlying error, when this diagnostic reports a failure. |
code | ThemeDiagnosticCode | Stable identifier. Safe to assert on in tests and to filter by. |
context (optional) | ThemeDiagnosticContext | Structured context, when the diagnostic has any. |
docs (optional) | string | Link to the reference entry for this code. Derived from code. |
hint (optional) | string | What to do instead. Present only when there is a concrete correction. |
level | ThemeDiagnosticLevel | How serious this is, and what the caller should do about it. |
message | string | A concise, actionable description of what is wrong. |
ThemeDiagnosticContext
Structured, machine-readable context for a diagnostic.
Every field is optional because a diagnostic should carry only what it actually knows. The point of the structure is that a caller can act on the failure without parsing prose.
See also: ThemeDiagnostic
| Member | Type | Description |
|---|---|---|
api (optional) | string | The public API involved, e.g. "setMode". |
details (optional) | unknown | Extra structured payload the diagnostic carries. Used when the evidence is more than a single offending value — a list of failing checks, for example. It is emitted as part of the diagnostic object so the detail is available without being flattened into prose. |
expected (optional) | string | The value(s) that were expected, as a human-readable description. |
path (optional) | string | A path into the offending input, e.g. "colors.primary". |
property (optional) | string | The property or argument at fault, e.g. "mode". |
received (optional) | unknown | The value that was received. Omitted when it cannot be serialised usefully. |
ThemeDiff
What actually changed between two themes, grouped by token category.
Produced by the Theme Diff Engine. Every downstream stage (planner, scanner, coordinator) keys off these booleans so Themvora only animates the token groups that really changed — never a blanket transition.
See also: createThemeDiff
| Member | Type | Description |
|---|---|---|
borders | boolean | Whether border tokens changed. |
colors | boolean | Whether color tokens changed. |
layout | boolean | Non-animatable groups (z-index, breakpoints) that require an instant swap + relayout rather than an animation. |
radius | boolean | Whether radius tokens changed. |
shadows | boolean | Whether shadow tokens changed. |
spacing | boolean | Whether spacing tokens changed. |
transforms | boolean | Whether transform tokens changed. |
typography | boolean | Whether typography tokens changed. |
ThemeDiffOptions
Options for diffThemes.
| Member | Type | Description |
|---|---|---|
includeUnchanged (optional) | boolean | Include unchanged entries in changes. Never affects counts. |
modes (optional) | readonly "light" | "dark"[] | Restrict the comparison to these visual modes. Omit to compare every mode present on either side. |
prefersDark (optional) | boolean | Whether the visitor prefers dark. Consulted only when a side declares mode: "system", i.e. only by the selector. An explicit option rather than an ambient read, so the result stays deterministic. |
themes (optional) | readonly ThemeDefinition<string>[] | Registry used to resolve extends on either side, and to resolve a mode: "system" selector. Mirrors the themes option on validateTheme. |
ThemeDiffProvenance
Provenance differences, reported separately from token changes.
hasChanges deliberately ignores this: two themes with identical tokens but
different seeds render identically, so reporting them as different would be
wrong for the primary use case.
| Member | Type | Description |
|---|---|---|
a | ThemeGenerationProvenance | null | Provenance on side a, or null. |
b | ThemeGenerationProvenance | null | Provenance on side b, or null. |
changed | boolean | Whether the two sides' provenance differs. |
differing | readonly string[] | The provenance field names that differ, sorted. |
ThemeDiffReport
The full diff report.
| Member | Type | Description |
|---|---|---|
a | ThemeDiffSide | Side a. |
b | ThemeDiffSide | Side b. |
hasChanges | boolean | Whether any token value differs. Provenance is reported separately. |
modes | Partial<Record<"light" | "dark", ThemeModeDiff>> | Keyed by concrete visual mode. A "system" key cannot exist. |
provenance | ThemeDiffProvenance | Provenance differences. |
summary | ThemeModeDiffCounts | The union of every mode's counts. |
version | 1 | The report schema version. Independent of the theme schema and package versions. |
ThemeDiffSide
One side of a diff: a resolved theme identity.
| Member | Type | Description |
|---|---|---|
family | string | The theme family, via getThemeFamily. |
mode | "light" | "dark" | The concrete visual mode. Never "system": a "system" selector is resolved before the comparison, so this always names the theme that was actually compared. |
name | string | The theme name that was compared. |
ThemeEffectiveSelection
The appearance actually on screen, as distinct from the selection that was configured.
A ThemeSelectionState is a request — { family: "plum", mode: "system" } says "give me the plum family and follow the operating system".
The effective selection is what that request resolved to once every automatic
driver had its say: prefers-color-scheme for "system", or the
sunrise/sunset schedule when one is running. Its mode is therefore never
"system", and its family is the family of the theme that is actually
applied — which can differ from the requested family when an automatic driver
applies a theme from another one.
Keeping the two apart is what lets a control show the real appearance while
setMode/setFamily still report and edit the visitor's choice. They agree
whenever no automatic driver is running, and diverge exactly while one is.
See also: ThemeSelectionState
| Member | Type | Description |
|---|---|---|
family | string | Family of the theme that is actually applied. |
mode | "light" | "dark" | Mode of the theme that is actually applied — never "system". |
ThemeErrorOptions
Options for ThemeError.
| Member | Type | Description |
|---|---|---|
cause (optional) | unknown | The underlying error, when this one wraps a failure. |
code (optional) | ThemeDiagnosticCode | Stable diagnostic code, when this error corresponds to one. |
context (optional) | ThemeDiagnosticContext | Structured context, when the error has any. |
ThemeGenerationInput
The statically readable inputs of a generateTheme() call.
| Member | Type | Description |
|---|---|---|
readonly algorithm (optional) | string | — |
readonly contrast (optional) | string | — |
readonly family (optional) | string | — |
readonly seed | string | — |
readonly style (optional) | string | — |
readonly withCode (optional) | boolean | — |
ThemeGenerationProvenance
Generation provenance for one side, or null when the theme has none.
| Member | Type | Description |
|---|---|---|
algorithm | string | The generation algorithm, e.g. "semantic-v2". |
anchored | readonly string[] | Roles pinned to a brand anchor rather than generated. |
seed | string | The seed the theme was generated from. |
style | string | null | The generation style, when one was recorded. |
ThemeHistory<T extends ThemeDefinition>
Undo/redo history bound to a theme store.
Every theme change (outside of undo/redo/restore operations) appends an entry and truncates any redo branch. Entries are deep-cloned on read so callers cannot mutate recorded states.
| Member | Type | Description |
|---|---|---|
canRedo | boolean | — |
canUndo | boolean | — |
clear | void | — |
destroy | void | — |
getHistory | HistoryEntry<T>[] | — |
jump | void | — |
redo | void | — |
undo | void | — |
ThemeHistoryOptions
Options for creating a theme history controller.
| Member | Type | Description |
|---|---|---|
maxSteps (optional) | number | Maximum number of history entries retained (including the initial entry). When the limit is exceeded, the oldest entries are dropped. |
now (optional) | __type(): number | The clock used to timestamp entries. |
ThemeInspectorProps
Props accepted by the Vue <ThemeInspector> component.
| Member | Type | Description |
|---|---|---|
bottom (optional) | number | Distance from the bottom of the viewport, in px. Default 104. |
right (optional) | number | Distance from the right edge of the viewport, in px. Default 32. |
size (optional) | number | Toggle button size, in px. Default 40. |
zIndex (optional) | number | Z-index for the floating toggle and panel. Default 9999. |
ThemeLifecycle<T extends ThemeDefinition>
Typed event emitter for runtime lifecycle events.
Hooks are invoked synchronously in registration order.
| Member | Type | Description |
|---|---|---|
emit | __type<K extends keyof ThemeLifecycleEventMap<ThemeDefinition<string>>>(event: K, data: ThemeLifecycleEventMap<T>[K]): void | Synchronously emits an event to all registered handlers. |
off | __type<K extends keyof ThemeLifecycleEventMap<ThemeDefinition<string>>>(event: K, handler: __type(data: ThemeLifecycleEventMap<T>[K]): void): void | Removes a previously registered handler. No-op when the handler is not registered. |
on | __type<K extends keyof ThemeLifecycleEventMap<ThemeDefinition<string>>>(event: K, handler: __type(data: ThemeLifecycleEventMap<T>[K]): void): __type(): void | Registers a handler for a lifecycle event. |
destroy | void | — |
ThemeLifecycleEventMap<T extends ThemeDefinition>
Payload shapes for each lifecycle event.
beforeThemeChange/afterThemeChangefire around theme transitions.beforePersist/afterPersistfire around persistence writes.beforeApply/afterApplyfire around DOM/CSS application.
| Member | Type | Description |
|---|---|---|
afterApply | { theme: T } | Fired after the theme was applied to the DOM/CSS bindings. |
afterPersist | { selection: ThemeSelectionState } | Fired after the selection was persisted. |
afterThemeChange | { theme: T } | Fired after the active theme changed. |
beforeApply | { theme: T } | Fired before the theme is applied to the DOM/CSS bindings. |
beforePersist | { selection: ThemeSelectionState } | Fired before the selection is persisted. |
beforeThemeChange | { current: T; next: T } | Fired before the active theme changes. |
ThemeMeta
Metadata describing a theme's family, mode, and presentation.
family and mode drive selection; the remaining fields are descriptive
and may be surfaced by tooling, the inspector, or docs generators.
See also: ThemeDefinition
| Member | Type | Description |
|---|---|---|
created (optional) | string | ISO date the theme was created. |
description (optional) | string | Short human-readable description of the theme. |
family (optional) | string | Theme family used for selection and toggling. Themes without a family belong to the "default" family. |
generation (optional) | GenerationMeta | Generation provenance, present only on generated themes. |
group (optional) | string | Deprecated alias for family. Prefer family. |
label (optional) | string | Human-readable theme name shown in pickers and the inspector. |
mode (optional) | "light" | "dark" | "system" | Color mode of the theme. When omitted, the mode is inferred from the theme name (e.g. "mint-dark" → "dark"). |
order (optional) | number | Relative sort order among themes of the same family. |
tags (optional) | string[] | Free-form tags for filtering and classification. |
updated (optional) | string | ISO date the theme was last updated. |
version (optional) | string | Theme schema version this definition targets. |
ThemeModeControllerOptions<T extends ThemeDefinition>
Options for createThemeModeController.
The controller resolves a theme mode (light | dark | system) into a
concrete theme applied to the store, optionally persisting the mode and
broadcasting it across tabs/windows.
| Member | Type | Description |
|---|---|---|
broadcast (optional) | ThemeBroadcastAdapter | null | Adapter used to broadcast and observe the mode across tabs/windows. When null, broadcasting is disabled. |
darkTheme | T | Theme applied when the resolved mode is dark. |
initialMode (optional) | ThemeMode | Initial mode used when persistence is not read (or has no value). |
lightTheme | T | Theme applied when the resolved mode is light. |
persistence (optional) | ThemePersistenceAdapter | null | Adapter used to persist and observe the mode. When null, persistence is disabled. |
readPersistenceOnInit (optional) | boolean | Whether to read the persisted mode on creation. |
store | ThemeStore<T> | The store the resolved theme is applied to. |
view (optional) | Window | The Window used for the system binding. Defaults to the global window when present. |
ThemeModeDiff
The diff for one visual mode.
| Member | Type | Description |
|---|---|---|
byGroup | readonly ThemeModeGroupCounts[] | Per-group counts, in TOKEN_GROUPS order, for groups present on either side. |
changes | readonly ThemeTokenChange[] | The changes, filtered by includeUnchanged. |
counts | ThemeModeDiffCounts | The counts. Never filtered. |
mode | "light" | "dark" | The concrete visual mode. "system" is a selector, not a mode. |
present | "both" | "a" | "b" | Which sides provide this mode. |
ThemeModeDiffCounts
Per-status counts. Always complete, whatever includeUnchanged is set to.
| Member | Type | Description |
|---|---|---|
added | number | Paths present only on b. |
changed | number | Paths present on both with different resolved values. |
removed | number | Paths present only on a. |
total | number | Every path seen on either side. |
unchanged | number | Paths present on both with the same resolved value. |
ThemeModeGroupCounts
Extends Omit<ThemeModeDiffCounts, "total">
Per-group counts.
| Member | Type | Description |
|---|---|---|
added | number | Paths present only on b. |
changed | number | Paths present on both with different resolved values. |
group | "code" | "colors" | "spacing" | "radius" | "shadows" | "borderWidths" | "zIndex" | "breakpoints" | "typography" | The token group. |
removed | number | Paths present only on a. |
unchanged | number | Paths present on both with the same resolved value. |
ThemeOverrideSelection
A family/mode request. Either field may be omitted; the omitted one is taken from the selection the provider would otherwise have used.
See also: ThemeOverride
| Member | Type | Description |
|---|---|---|
family (optional) | string | Theme family to apply. Must be one the provider was given. |
mode (optional) | ThemeMode | Mode to apply within the family. |
ThemePersistenceAdapter
A contract for persisting and observing the selected theme mode.
get returns null when nothing is stored or the stored value is not a
valid mode. subscribe returns an unsubscribe function.
| Member | Type | Description |
|---|---|---|
get | ThemeMode | null | — |
remove | void | — |
set | void | — |
subscribe | __type(): void | — |
ThemePersistenceOptions
Options for createThemePersistence.
The adapter persists the theme mode to a Storage (default
localStorage) and observes cross-tab changes via the storage event.
| Member | Type | Description |
|---|---|---|
key (optional) | string | Storage key used for the persisted mode. |
storage (optional) | Storage | The Storage to read/write. Defaults to view.localStorage. |
view (optional) | Window | The Window used to access storage and listen for storage events. Defaults to the global window when present. |
ThemePlugin<T extends ThemeDefinition>
Extends ThemePluginHooks<T>
A named, versioned unit of behavior that hooks into the theme runtime.
A plugin combines a unique name with any subset of ThemePluginHooks
to observe or alter theme selection, persistence, application, and lifecycle.
Plugins are registered through a PluginManager.
| Member | Type | Description |
|---|---|---|
name | string | Unique plugin identifier used for registration, lookup, and removal. |
onAfterApply (optional) | __type(data: { theme: T }): void | Called after the active theme's tokens are applied to the runtime. |
onAfterPersist (optional) | __type(data: { selection: ThemeSelectionState }): void | Called after a theme selection is persisted. |
onAfterThemeChange (optional) | __type(data: { theme: T }): void | Called after the active theme changes, with the newly active theme. |
onBeforeApply (optional) | __type(data: { theme: T }): void | Called before the active theme's tokens are applied to the runtime. |
onBeforePersist (optional) | __type(data: { selection: ThemeSelectionState }): void | Called before a theme selection is persisted. |
onBeforeThemeChange (optional) | __type(data: { current: T; next: T }): void | Called before the active theme changes, with the current and next theme. |
onDestroy (optional) | __type(): void | Called when the plugin is removed or the manager is destroyed. |
onRuntimeCreated (optional) | __type(runtime: ThemeRuntime<T>): void | __type(): void | Called once when the runtime is created. May return a disposer invoked on plugin removal or manager destruction. |
priority (optional) | number | Execution order for hooks; lower values run first. Default 10. |
transformTokens (optional) | __type(tokens: ThemeTokens, context: { theme: T }): ThemeTokens | Transforms the theme's tokens before they are applied. Must return the (possibly modified) token set. |
version (optional) | string | Semantic version of the plugin. |
name must be unique within a manager; registering a duplicate name is
ignored. priority orders hook execution (lower runs first, default 10).
ThemePluginHooks<T extends ThemeDefinition>
Lifecycle hooks a plugin may implement to participate in the theme runtime.
Hooks are invoked by the plugin manager in a deterministic order: creation
and destruction hooks run once per plugin, while change/persist/apply hooks
run in plugin priority order (ascending priority, default 10). All hooks
are optional; a plugin implements only the ones it needs.
| Member | Type | Description |
|---|---|---|
onAfterApply (optional) | __type(data: { theme: T }): void | Called after the active theme's tokens are applied to the runtime. |
onAfterPersist (optional) | __type(data: { selection: ThemeSelectionState }): void | Called after a theme selection is persisted. |
onAfterThemeChange (optional) | __type(data: { theme: T }): void | Called after the active theme changes, with the newly active theme. |
onBeforeApply (optional) | __type(data: { theme: T }): void | Called before the active theme's tokens are applied to the runtime. |
onBeforePersist (optional) | __type(data: { selection: ThemeSelectionState }): void | Called before a theme selection is persisted. |
onBeforeThemeChange (optional) | __type(data: { current: T; next: T }): void | Called before the active theme changes, with the current and next theme. |
onDestroy (optional) | __type(): void | Called when the plugin is removed or the manager is destroyed. |
onRuntimeCreated (optional) | __type(runtime: ThemeRuntime<T>): void | __type(): void | Called once when the runtime is created. May return a disposer invoked on plugin removal or manager destruction. |
transformTokens (optional) | __type(tokens: ThemeTokens, context: { theme: T }): ThemeTokens | Transforms the theme's tokens before they are applied. Must return the (possibly modified) token set. |
onRuntimeCreated may return a disposer function that is called when the
plugin is removed or the manager is destroyed. onDestroy is invoked for
every registered plugin when the manager is destroyed.
ThemeProviderProps<T extends ThemeDefinition>
Extends ThemeRuntimeOptions<T>
Props accepted by the Vue <ThemeProvider> component.
Extends ThemeRuntimeOptions with an optional pre-built runtime. When
runtime is omitted, the provider creates and owns its own runtime from the
remaining props and destroys it on unmount.
| Member | Type | Description |
|---|---|---|
adapters (optional) | ThemeAdapter<T>[] | Library adapters installed when the runtime is created. The runtime owns the registry and notifies every adapter whenever the theme changes; it never knows anything about the libraries themselves. |
broadcast (optional) | ThemeSelectionBroadcastAdapter | null | Cross-tab broadcast adapter. When omitted, a BroadcastChannel-based adapter on channel "theme-selection" is created; pass null to disable cross-tab sync. |
cssVariables (optional) | false | CSSVariablesOptions | CSS-variable binding configuration. false disables the binding. |
defaultTheme (optional) | ThemeIdentifier<T> | Theme to activate when no persisted or explicit selection exists. Accepts a variant name ("cocoa-dark") or a family name ("cocoa"); a family resolves to the variant the mode contract picks (see resolveThemeReference). A variant also supplies its own mode unless initialMode is given. |
dom (optional) | false | DOMBindingOptions | DOM attribute/class binding configuration. false disables the binding. |
initial (optional) | InitialThemeResolution<T> | Explicit initial theme resolution, bypassing default + persistence based resolution. |
initialFamily (optional) | ThemeIdentifier<T> | Initial family used when nothing else is given. A variant name is also accepted and normalised to its family; the variant's own mode is used only when initialMode is absent, so an explicit mode always wins and the two props cannot silently disagree. |
initialMode (optional) | ThemeMode | Initial mode used when nothing else is given. |
persistence (optional) | ThemeSelectionPersistenceAdapter | null | Persistence adapter for the theme selection. Pass null to disable persistence entirely. |
plugins (optional) | ThemePlugin<T>[] | Runtime plugins installed at creation. |
readPersistenceOnInit (optional) | boolean | Whether a persisted selection is read at runtime creation. |
runtime (optional) | ThemeRuntime<T> | An existing runtime to provide. When omitted, the provider creates and owns a runtime from the other props. |
scheduled (optional) | false | ScheduledThemeOptions<T> | Sunrise/sunset scheduling configuration. false disables scheduling. |
themeOverride (optional) | ThemeOverride<ThemeIdentifier<T>> | An explicit theme to apply, outranking a saved selection. Unlike defaultTheme, which is only a fallback, an override is applied even when localStorage or a cookie already names another theme — which is what makes "preview this theme" expressible as a prop. It is a one-shot signal, not a controlled selection: it is applied when its value changes, it is never re-asserted on later renders, and it does not write to persistence. See ThemeOverride. |
themes (optional) | readonly T[] | Initial theme definitions. Duplicate names are dropped (first wins). When omitted, the registry starts empty. |
transition (optional) | boolean | ThemeTransitionOptions | Transition configuration. true enables transitions with defaults, false disables them, and an object provides explicit options. |
view (optional) | Window | The window to bind to. Defaults to the global window when available; omit (or pass undefined) in SSR environments. |
ThemeRegistryOptions<T extends ThemeDefinition>
Options for creating a theme registry.
| Member | Type | Description |
|---|---|---|
themes (optional) | readonly T[] | Initial theme definitions. Duplicate names are dropped (first wins). When omitted, the registry starts empty. |
ThemeRuntime<T extends ThemeDefinition>
A Themvora runtime — the single entry point for theming one application boundary.
A runtime owns theme selection, token resolution, persistence bindings, scheduling, lifecycle events, history, DOM/CSS-variable application, and adapter registration. Destroy the runtime when its owning application lifecycle ends.
See also: createThemeRuntime, ThemeRuntimeOptions
| Member | Type | Description |
|---|---|---|
adapters | AdapterRegistry<T> | The adapter registry (library adapters installed via runtime.use). |
history | ThemeHistory<T> | Undo/redo history of theme changes. |
readonly initial | ThemeRuntimeInitial<T> | The state a server render produces — the value useSyncExternalStore needs as its server snapshot. Read-only and frozen at creation. |
lifecycle | ThemeLifecycle<T> | Typed lifecycle event emitter. |
registry | ThemeRegistry<T> | The theme registry holding the registered definitions. |
readonly schedule | ThemeSchedule | null | The sunrise/sunset scheduling controller created from the scheduled runtime option. null when the runtime was created without one. Live: re-read after ThemeRuntime.configure with a scheduled update — the schedule is created, reconfigured in place, or torn down depending on the value. |
selection | { applyAutomaticTheme: __type(theme: T, opts?: { suppressTransition?: boolean }): void; applyState: __type(nextState: ThemeSelectionState, opts?: { persist?: boolean; suppressTransition?: boolean }): void; setAutomaticDriverActive: __type(active: boolean): void; setFamily: __type(nextFamily: string): void; setMode: __type(nextMode: ThemeMode): void; toggleTheme: __type(): void; destroy: void; getEffectiveMode: void; getEffectiveSelection: void; getFamily: void; getMode: void; getSelection: void; subscribe: void; subscribeEffective: void } | The selection controller (mode/family/system binding, persistence). |
store | ThemeStore<T> | The underlying theme store (current theme + subscription). |
readonly themes | readonly T[] | Live view of the registered themes. One array, kept in place: a consumer that reads it once and holds the reference still sees a later configure(), and a consumer that reads it on every change does not miss one. configure() replaces its contents rather than swapping the reference. |
readonly transition (optional) | ThemeTransitionOptions | The resolved theme-transition options the runtime was created with (undefined when none were supplied). Components like ThemeScope read this so scoped theme changes inherit the same transition as the provider. Live: ThemeRuntime.configure with a transition update replaces this value and pushes it into the runtime's live DOM/CSS bindings. |
batch | void | — |
configure | void | — |
destroy | void | — |
restore | void | — |
snapshot | ThemeRuntimeSnapshot<T> | — |
update | void | — |
use | void | — |
ThemeRuntimeInitial<T extends ThemeDefinition>
Extends InitialThemeResolution<T>
The state a server render produces: the fallback resolution with no
persisted override and no OS preference resolved, plus the history state
captured before the initial selection was applied.
See also: ThemeRuntime.initial
| Member | Type | Description |
|---|---|---|
canRedo | boolean | Whether ThemeHistory.redo would have an effect on the server. |
canUndo | boolean | Whether ThemeHistory.undo would have an effect on the server. |
history | HistoryEntry<T>[] | The history a server render produces: a single entry holding the server-resolved theme. |
selection | ThemeSelectionState | The resolved selection (family + mode). |
theme | T | The theme to activate. |
This is what React's useSyncExternalStore must be given as its server
snapshot. The runtime's live state cannot serve that purpose: by the time a
client component renders, the runtime has already adopted the persisted
selection and resolved prefers-color-scheme, so handing the live state to
getServerSnapshot makes React compare it against markup the server
rendered from the fallback — a mismatch, reported as React error #418,
that discards the server HTML and re-renders the whole island.
A server has neither a persisted selection (no storage) nor an OS
preference (no matchMedia), so the server snapshot is exactly the
fallback: options.initial when the caller resolved one, otherwise the
defaultTheme/initialFamily/initialMode resolution with prefersDark
pinned to false.
ThemeRuntimeOptions<T extends ThemeDefinition>
Extends ThemeRegistryOptions<T>
Configuration for creating a Themvora runtime.
Every option is optional; the runtime falls back to built-in themes, localStorage persistence, and default bindings when an option is omitted.
See also: createThemeRuntime
| Member | Type | Description |
|---|---|---|
adapters (optional) | ThemeAdapter<T>[] | Library adapters installed when the runtime is created. The runtime owns the registry and notifies every adapter whenever the theme changes; it never knows anything about the libraries themselves. |
broadcast (optional) | ThemeSelectionBroadcastAdapter | null | Cross-tab broadcast adapter. When omitted, a BroadcastChannel-based adapter on channel "theme-selection" is created; pass null to disable cross-tab sync. |
cssVariables (optional) | false | CSSVariablesOptions | CSS-variable binding configuration. false disables the binding. |
defaultTheme (optional) | ThemeIdentifier<T> | Theme to activate when no persisted or explicit selection exists. Accepts a variant name ("cocoa-dark") or a family name ("cocoa"); a family resolves to the variant the mode contract picks (see resolveThemeReference). A variant also supplies its own mode unless initialMode is given. |
dom (optional) | false | DOMBindingOptions | DOM attribute/class binding configuration. false disables the binding. |
initial (optional) | InitialThemeResolution<T> | Explicit initial theme resolution, bypassing default + persistence based resolution. |
initialFamily (optional) | ThemeIdentifier<T> | Initial family used when nothing else is given. A variant name is also accepted and normalised to its family; the variant's own mode is used only when initialMode is absent, so an explicit mode always wins and the two props cannot silently disagree. |
initialMode (optional) | ThemeMode | Initial mode used when nothing else is given. |
persistence (optional) | ThemeSelectionPersistenceAdapter | null | Persistence adapter for the theme selection. Pass null to disable persistence entirely. |
plugins (optional) | ThemePlugin<T>[] | Runtime plugins installed at creation. |
readPersistenceOnInit (optional) | boolean | Whether a persisted selection is read at runtime creation. |
scheduled (optional) | false | ScheduledThemeOptions<T> | Sunrise/sunset scheduling configuration. false disables scheduling. |
themeOverride (optional) | ThemeOverride<ThemeIdentifier<T>> | An explicit theme to apply, outranking a saved selection. Unlike defaultTheme, which is only a fallback, an override is applied even when localStorage or a cookie already names another theme — which is what makes "preview this theme" expressible as a prop. It is a one-shot signal, not a controlled selection: it is applied when its value changes, it is never re-asserted on later renders, and it does not write to persistence. See ThemeOverride. |
themes (optional) | readonly T[] | Initial theme definitions. Duplicate names are dropped (first wins). When omitted, the registry starts empty. |
transition (optional) | boolean | ThemeTransitionOptions | Transition configuration. true enables transitions with defaults, false disables them, and an object provides explicit options. |
view (optional) | Window | The window to bind to. Defaults to the global window when available; omit (or pass undefined) in SSR environments. |
ThemeRuntimeSnapshot<T extends ThemeDefinition>
A serializable snapshot of a runtime's state.
Produced by ThemeRuntime.snapshot and accepted by ThemeRuntime.restore for time-travel and state transfer.
| Member | Type | Description |
|---|---|---|
history | HistoryEntry<T>[] | Recorded history entries. |
registry | { themes: T[] } | The registry contents at snapshot time. |
selection | ThemeSelectionState | The active selection (family + mode). |
theme | T | The active theme definition. |
ThemeSchedule
A framework-neutral sunrise/sunset scheduling controller.
Exposes an explicit on/off switch and a reactive state snapshot
(sunrise, sunset, nextTransition, ...) so frameworks can surface it
through their native accessors. destroy is idempotent and releases the
underlying binding and store subscription.
| Member | Type | Description |
|---|---|---|
readonly active | boolean | Whether the schedule is enabled AND the currently applied theme is one of the scheduled light/dark themes. |
readonly autoDetected | boolean | Whether the coordinates were resolved from a timezone rather than explicit coordinates. |
readonly darkTheme | string | null | The theme applied between sunset and sunrise, or null when not derived yet. |
readonly enabled | boolean | Whether the schedule is currently enabled. |
readonly latitude | number | null | The resolved latitude used for solar calculations. |
readonly lightTheme | string | null | The theme applied between sunrise and sunset, or null when not derived yet. |
readonly longitude | number | null | The resolved longitude used for solar calculations. |
readonly nextActivation | Date | null | The next time the scheduled theme becomes active, or null. |
readonly nextDeactivation | Date | null | The next time the scheduled theme stops being active, or null. |
readonly nextTransition | ThemeScheduleTransition | null | The light→dark or dark→light transition time and target, or null while the schedule is disabled. |
readonly state | ThemeScheduleState | The current reactive state snapshot (stable reference between changes). |
readonly status | ThemeScheduleStatus | "active" when enabled, "disabled" otherwise. |
readonly sunrise | Date | null | Today's sunrise time, or null when unresolvable. |
readonly sunset | Date | null | Today's sunset time, or null when unresolvable. |
readonly timeZone | string | null | The timezone the coordinates were resolved from, or null when explicit coordinates are in use. |
destroy | void | — |
disable | void | — |
enable | void | — |
set | void | — |
setLastSyncTime | void | — |
subscribe | __type(): void | — |
ThemeScheduleController
Controller returned by useThemeSchedule for the runtime's sunrise/sunset scheduling engine.
See also: useThemeRuntime
| Member | Type | Description |
|---|---|---|
disable | __type(): void | Disables the schedule engine. |
enable | __type(): void | Enables the schedule engine. |
schedule | ThemeSchedule | null | The underlying controller (null when the provider has no scheduled option). Methods below are safe no-ops in that case. |
set | __type(options: ThemeScheduleSetOptions): void | Updates the schedule configuration. |
state | Ref<ThemeScheduleState> | Reactive state snapshot: enabled, active, status, sunrise, sunset, nextTransition, nextActivation, nextDeactivation. |
ThemeScheduleOptions<T extends ThemeDefinition>
Options for createThemeSchedule.
The schedule applies a light theme during daytime and a dark theme at
night, based on sunrise/sunset at a resolved location. lightTheme and
darkTheme are optional: when omitted they are derived from the currently
selected theme's family (falling back to the built-in neutral light/dark
themes) and re-resolved whenever the user switches theme family.
| Member | Type | Description |
|---|---|---|
autoDetectLocation (optional) | boolean | Auto-detect the visitor's location from their browser timezone when no explicit coordinates/timezone are given. Default true. |
checkInterval (optional) | number | How often (ms) the schedule re-checks solar time. Default 60000. |
darkTheme (optional) | T["name"] | Theme applied between sunset and sunrise. Optional — same derivation as lightTheme, falling back to the built-in neutral "dark" theme. |
enabled (optional) | boolean | Start enabled. Default true. |
getTimes (optional) | __type(date: Date, latitude: number, longitude: number): { sunrise: Date; sunset: Date } | Override the NOAA solar math. Defaults to calculateSunTimes. |
latitude (optional) | number | Explicit latitude. Optional — when omitted the location is resolved from timeZone or the visitor's browser timezone. |
lightTheme (optional) | T["name"] | Theme applied between sunrise and sunset. Optional — when omitted the schedule derives it from the currently selected theme's family (or falls back to the built-in neutral "light" theme), so it adapts as the user switches theme families. |
longitude (optional) | number | Explicit longitude. Optional — see latitude. |
onBeforeApply (optional) | __type(theme: T): boolean | Called before the schedule applies a theme. Return false to block the switch for this cycle. |
skipApplyMs (optional) | number | Ignore schedule-driven applies within this many ms after a manual selection (e.g. a cross-tab sync). Default 0. |
timeZone (optional) | string | IANA timezone to resolve coordinates from when latitude/longitude are omitted (e.g. "Asia/Kathmandu"). Takes precedence over auto-detection. |
ThemeScheduleSetOptions
Extends SolarLocationInput
Options for ThemeSchedule.set.
Repositions the schedule (explicit coordinates take precedence over an
explicit timeZone, which takes precedence over auto-detection),
reconfigures its interval/skip window, and/or toggles its enabled state.
| Member | Type | Description |
|---|---|---|
autoDetectLocation (optional) | boolean | Auto-detect the visitor's location from their browser timezone when no explicit coordinates/timezone are given. Default true. On the server (no window) detection is skipped and the default coordinates are used so SSR output stays deterministic. |
checkInterval (optional) | number | How often (ms) the schedule re-checks solar time. |
darkTheme (optional) | string | Scheduled nighttime theme name. See lightTheme. |
enabled (optional) | boolean | Whether the schedule should be enabled after the update. |
latitude (optional) | number | Explicit latitude. When present (alone or with longitude) it wins over timezone resolution. |
lightTheme (optional) | string | Scheduled daytime theme name. Presence-based rather than !== undefined: passing the key explicitly — even as undefined — clears an earlier explicit name and returns to deriving the pair from the current theme family. Omitting the key leaves the current name alone. |
longitude (optional) | number | Explicit longitude. When present (alone or with latitude) it wins over timezone resolution. |
skipApplyMs (optional) | number | Ignore schedule-driven applies within this many ms after a manual selection. |
timeZone (optional) | string | IANA timezone to resolve coordinates from (e.g. "Asia/Kathmandu"). Takes precedence over auto-detection. |
ThemeScheduleState
Reactive snapshot of a ThemeSchedule. Emitted to subscribers whenever the
enabled state, applied theme or solar times change.
| Member | Type | Description |
|---|---|---|
active | boolean | Whether the schedule is enabled AND the currently applied theme is one of its scheduled light/dark themes (i.e. the schedule is actually driving the selection right now, not manually overridden). |
autoDetected | boolean | Whether the coordinates were resolved from a timezone (explicit timeZone or browser auto-detection) rather than explicit coordinates. |
darkTheme | string | null | The theme applied at night. |
enabled | boolean | Whether the schedule is enabled. |
latitude | number | null | The resolved latitude used for solar calculations (from explicit coordinates, an explicit timeZone, or browser auto-detection). |
lightTheme | string | null | The theme applied during daytime. |
longitude | number | null | The resolved longitude used for solar calculations. |
nextActivation | Date | null | Next time the light theme will be activated. |
nextDeactivation | Date | null | Next time the dark theme will be activated. |
nextTransition | ThemeScheduleTransition | null | The next automatic light/dark switch, with the theme it will apply. |
status | ThemeScheduleStatus | "active" when enabled, "disabled" otherwise. |
sunrise | Date | null | Today's sunrise (or the sunrise of the day state was computed for). |
sunset | Date | null | Today's sunset. |
timeZone | string | null | The timezone the coordinates were resolved from, or null when explicit coordinates are in use (or detection wasn't possible — e.g. on the server). |
ThemeScheduleTransition
Describes the next automatic light/dark switch of a ThemeSchedule.
| Member | Type | Description |
|---|---|---|
at | Date | When the next automatic change happens. |
theme | string | Theme that will be applied at at. |
type | "activation" | "deactivation" | "activation" → light theme at sunrise; "deactivation" → dark theme at sunset. |
ThemeScopeProps
Props accepted by the Vue <ThemeScope> component.
| Member | Type | Description |
|---|---|---|
family (optional) | string | Theme family for the scoped subtree. Without mode, follows the provider's current mode. |
mode (optional) | ThemeMode | Mode for a family-based scope. Defaults to the provider's current mode. |
theme (optional) | string | Exact theme name or family name. When family/mode are also set, theme wins. Omit to follow the provider's selection inside a boundary. |
themes (optional) | readonly ThemeDefinition<string>[] | Local theme definitions — resolved first, parent registry falls back. No second runtime is created. |
transition (optional) | boolean | ThemeTransitionOptions | Transition for this scope. undefined inherits the provider's, false disables it, an object is merged over the provider config. |
ThemeScrollbarProps
Extends ScrollbarGroupedOptions
Props accepted by the Vue <ThemeScrollbar> component.
Extends OverlayScrollbarOptions with an optional custom element tag.
| Member | Type | Description |
|---|---|---|
appearance (optional) | ScrollbarAppearanceOptions | — |
behavior (optional) | ScrollbarBehaviorOptions | — |
icons (optional) | ScrollbarIconOptions<string> | Arrow button icons: the arrow entry covers all four directions (per-direction entries win), plus the shared glyph size in CSS px. |
scope (optional) | ScrollbarScopeOptions | — |
tag (optional) | string | The element tag to apply the overlay scrollbar to. Defaults to the provider's scroll container. |
ThemeSelectionBroadcastOptions
Options for createThemeSelectionBroadcast.
The adapter publishes the full theme selection (mode + family) to a
BroadcastChannel and applies incoming selections from other
tabs/windows.
| Member | Type | Description |
|---|---|---|
channel (optional) | BroadcastChannelLike<ThemeSelectionState> | A custom channel to use. When omitted, a BroadcastChannel is created from channelName. |
channelName (optional) | string | Name of the BroadcastChannel created when channel is omitted. |
ThemeSelectionPersistenceAdapter
A contract for persisting and observing the full theme selection (mode + family).
get returns null when nothing is stored or the stored value is not a
valid selection. subscribe returns an unsubscribe function.
| Member | Type | Description |
|---|---|---|
get | ThemeSelectionState | null | — |
remove | void | — |
set | void | — |
subscribe | __type(): void | — |
ThemeSelectionState
The active selection: a family plus a color-mode.
Persistence adapters serialize this exact shape, so the fields are part of the storage contract.
See also: createThemeModeController
| Member | Type | Description |
|---|---|---|
family | string | Selected theme family. Themes without meta.family belong to the "default" family. |
mode | ThemeMode | Selected color mode. "system" tracks the visitor's prefers-color-scheme preference. |
ThemeSet
A light/dark theme set — the shape generate --mode both writes and
toThemes produces.
| Member | Type | Description |
|---|---|---|
dark (optional) | ThemeDefinition<string> | The dark theme, when the set has one. |
light (optional) | ThemeDefinition<string> | The light theme, when the set has one. |
ThemeStore<T extends ThemeDefinition>
The theme store: the runtime's single source of truth for the active theme.
The store is deliberately framework-free. Framework integrations wrap it with reactive bindings; the runtime wires persistence, transitions, and adapters around it.
| Member | Type | Description |
|---|---|---|
batch | void | — |
destroy | void | — |
get | T | — |
set | void | — |
subscribe | __type(): void | — |
ThemeStoreOptions<T extends ThemeDefinition>
Options for creating a theme store.
| Member | Type | Description |
|---|---|---|
initialTheme | T | The theme the store starts with. |
ThemeToCSSVariablesOptions
Options for themeToCSSVariables.
| Member | Type | Description |
|---|---|---|
groups (optional) | "code" | "colors" | "spacing" | "radius" | "shadows" | "borderWidths" | "zIndex" | "breakpoints" | "typography"[] | Restrict emission to the listed token groups. When omitted, all groups are emitted. |
prefix (optional) | string | CSS custom property prefix. The token group name is appended to it. |
ThemeTokenChange
One token path's outcome.
| Member | Type | Description |
|---|---|---|
after (optional) | string | The value on side b. Absent when the token was removed. |
before (optional) | string | The value on side a. Absent when the token was added. |
group | "code" | "colors" | "spacing" | "radius" | "shadows" | "borderWidths" | "zIndex" | "breakpoints" | "typography" | The token group the path belongs to. |
path | string | Dot-path into the token tree, e.g. "colors.primary". |
role | CoreColor | OptionalSemantic | null | The semantic role, when the path names a core or optional role. |
roleGroup | "canvas" | "surfaces" | "actions" | "states" | "interaction" | null | The role group the role belongs to, e.g. "actions". |
status | ThemeTokenChangeStatus | The outcome. |
ThemeTokens
Semantic token values consumed by the runtime.
Top-level groups map to CSS variable namespaces (--theme-color-*,
--theme-spacing-*, …) when bound to the DOM by the runtime.
See also: themeToCSSVariables, resolveTokens
| Member | Type | Description |
|---|---|---|
borderWidths (optional) | Record<string, string> | Border width values. |
breakpoints (optional) | Record<string, string> | Responsive breakpoint values. |
code (optional) | CodeTokens | Opt-in semantic colors for code and syntax surfaces. |
colors (optional) | ThemeColors | Semantic color values. |
radius (optional) | Record<string, string> | Border radius scale values. |
shadows (optional) | Record<string, string> | Shadow values (typically CSS box-shadow strings). |
spacing (optional) | Record<string, string> | Spacing scale values (typically CSS lengths). |
typography (optional) | { fontFamilies?: Record<string, string>; fontSizes?: Record<string, string>; lineHeights?: Record<string, string> } | Typography scale values. |
zIndex (optional) | Record<string, string> | Z-index values. |
ThemeTransitionOptions
Configures theme transition behavior.
Transition configuration is applied by the runtime when the active theme
changes. Individual updates may suppress the configured transition (see
suppressTransition).
See also: createTransitionPlan, runThemeAnimation
| Member | Type | Description |
|---|---|---|
duration (optional) | number | Transition duration in milliseconds. |
easing (optional) | string | CSS timing function used for the transition. |
enabled (optional) | boolean | Whether theme transitions are enabled. |
preset (optional) | TransitionPreset | Which properties are allowed to animate. "smooth"/"subtle" map to a curated color-property set, "instant" disables interpolation, and a raw array filters the diff-derived properties. |
properties (optional) | string[] | Explicit property allowlist. Overrides preset when provided. |
useViewTransition (optional) | boolean | Prefer the View Transition API when the browser supports it. When enabled and available, theme changes use a native view transition (a crossfade snapshot) instead of CSS-custom-property interpolation, avoiding intermediate gray washes during light↔dark switches. Falls back to @property-based interpolation when the API is unavailable or the user prefers reduced motion. |
ThemvoraConfig<T extends ThemeDefinition>
The application's Themvora configuration: one declaration, consumed by both the runtime and the pre-paint bootstrap.
See also: defineThemvoraConfig
| Member | Type | Description |
|---|---|---|
adapters (optional) | readonly unknown[] | Runtime adapters. Runtime-only, and not serializable — pass it to the provider, not here. |
defaultTheme (optional) | T["name"] | Theme name to fall back to when no selection is persisted. |
initialFamily (optional) | string | Family used when no selection is persisted. |
initialMode (optional) | ThemeMode | Mode used when no selection is persisted. Defaults to the fallback theme's own mode. |
persistence (optional) | unknown | Whether the selection is persisted across visits. false or null disables it. |
plugins (optional) | readonly unknown[] | Runtime plugins. Runtime-only, and not serializable — pass it to the provider, not here. |
prefix (optional) | string | CSS custom property prefix. Defaults to "theme-". |
scrollbar (optional) | unknown | Overlay scrollbar options. Serializable, so it crosses to the browser. |
storageKey (optional) | string | localStorage key holding the persisted selection. Defaults to "theme-selection". |
themes | readonly T[] | The theme definitions registered with the runtime. |
transition (optional) | unknown | Transition configuration. |
This exists to remove a class of bug rather than to add a feature. When the theme registry, the fallback theme and the initial mode are declared twice — once for the provider and once for whatever emits the pre-paint script — the two drift, and a drift is visible: the script paints one theme, the runtime corrects it a frame later, and any theme-name readout contradicts the control that set it.
Two projections read this object, and neither is a second declaration:
- the runtime projection — everything below, handed to
createThemeRuntime; - the transported projection — toBootstrapConfig, the serializable subset that crosses to the browser, where the pre-paint script and the client runtime both read it.
The second one is what makes the client runtime honour this file. It is not
only the pre-paint subset: a runtime option left out of it is not ignored, it
is replaced by a default, which is how a declared transition: { enabled: false } still produced a view transition on every theme change. See
ThemeBootstrapConfig.
ThemvoraThemeConfig<T extends ThemeDefinition>
The deprecated inline form of the theme configuration: the registry, the fallback theme, the initial mode/family, and the persistence key and prefix, passed straight to themvoraVitePlugin.
See also: themvoraVitePlugin
| Member | Type | Description |
|---|---|---|
defaultTheme (optional) | T["name"] | Theme name to fall back to when no persisted selection exists. |
initialFamily (optional) | string | Family used when no persisted selection exists. |
initialMode (optional) | ThemeMode | Mode used when no persisted selection exists. Defaults to the fallback theme's own mode — whatever defaultTheme resolves to, so a defaultTheme="light" app paints light from frame one. |
prefix (optional) | string | CSS custom property prefix. Defaults to "theme-". |
storageKey (optional) | string | localStorage key holding the persisted theme selection. Defaults to "theme-selection". |
themes | readonly T[] | The theme definitions registered with the runtime. |
TokenRemap
A single token rename applied during a migration step.
| Member | Type | Description |
|---|---|---|
from | string | The token key to rename from. |
to | string | The token key to rename to. |
TransitionPlan
The concrete, ready-to-apply transition decided by the Transition Planner.
rootProperties — registered --theme-color-* custom properties animated
directly on :root; descendants inherit the interpolated values.
elementProperties — real CSS properties (padding, border-radius, …)
transitioned on the scanned elements that actually use them.
See also: createTransitionPlan
| Member | Type | Description |
|---|---|---|
animatesColors | boolean | Whether the plan animates the theme's color custom properties. |
duration | number | Transition duration in milliseconds. |
easing | string | CSS timing function for the transition. |
elementProperties | string[] | Real CSS properties transitioned on the scanned elements that use them. |
ValidateThemeContrastOptions
Options for validateThemeContrast.
| Member | Type | Description |
|---|---|---|
themes (optional) | readonly ThemeDefinition<string>[] | Additional theme definitions used to resolve the target theme by name before checking. When omitted, the theme is checked as-is. |
ValidateThemeLevelsOptions
Options for validateThemeLevels.
| Member | Type | Description |
|---|---|---|
cvdTypes (optional) | readonly CVDType[] | The CVD types to diagnose against. Defaults to the two common ones. |
levels (optional) | readonly ValidationLevel[] | Which levels to run. Defaults to all of them. |
ValidateThemeOptions
Options for validateTheme.
| Member | Type | Description |
|---|---|---|
themes (optional) | readonly ThemeDefinition<string>[] | Additional theme definitions used to resolve the target theme by name before validation. When omitted, the theme is validated as-is. |
ValidationIssue
A single problem found while validating a theme definition.
| Member | Type | Description |
|---|---|---|
code | ThemeDiagnosticCode | Stable diagnostic code. Assert on this rather than on message, which may be reworded. |
context | ThemeDiagnosticContext | Structured context, so a caller can act without parsing message. |
message | string | Human-readable description of the issue. |
path | string | Dot-separated path to the offending token, e.g. "colors.primary". |
type | "missing" | The kind of issue. Currently always "missing" (a required token is absent). |
ValidationResult
The outcome of validating a theme definition.
| Member | Type | Description |
|---|---|---|
issues | ValidationIssue[] | Every issue found, empty when the theme is valid. |
valid | boolean | true when no issues were found. |
Type Aliases
AdapterStrategy
How faithfully an adapter reproduces the target library's native feel.
exact— only map what Themvora defines; change nothing.native— behave like the library: derive missing semantic concepts (e.g. success/warning/info) and make small feel adjustments.aggressive— fully emulate the library: also adjust spacing, typography, elevation, saturation and contrast.
"exact" | "native" | "aggressive"
AnimatedGroupKey
The name of an animatable token group.
typeof ANIMATED_GROUP_KEYS[number]
BrandColorClass
How a reference colour is used by the generator.
"ANCHOR" | "DERIVED" | "SEMANTIC" | "IMPLEMENTATION"
BrandProvenance
How faithful a brand recipe is to the real brand.
Required on brand recipes: a preset gallery that shows a company's colours without saying how it relates to the company is misleading.
"official" | "approximate" | "community-inspired" | "demonstration-only" | "unaffiliated"
BrandSourceKind
Where a brand's reference data came from.
official-guidelines and official-design-system are the strong sources: the
brand publishes the values and intends them to be used. web-reference is
weaker — a value observed on a site, which may change without notice.
"official-guidelines" | "official-design-system" | "web-reference"
CalculateSunTimesLocationOptions
Options accepted by calculateSunTimes for resolving a location when
latitude/longitude are omitted.
SolarLocationInput
CheckStatus
The outcome of one check.
"pass" | "warn" | "fail"
ContextLevel
Whether the generator promises the context, or merely reports it.
required— part of the shipped guarantee. A theme that fails is a bug.advisory— a use the system knows about and deliberately does not promise, because promising it would force brand colours to be desaturated. Reported so the failure is visible rather than silent.
"required" | "advisory"
ContextOwner
Who is responsible for keeping a context true.
The point of naming an owner is to make a bad screenshot cheap to triage. The first question is never "is the generator wrong?" — it is "whose promise is this?", and the answer decides whether the fix belongs in the colour engine, in a Themvora integration, or in the application that placed the role.
generator— the colour itself must satisfy the contract. Nothing outside the engine can fix a failure here.integration— Themvora's own runtime consumes the tokens and must choose a role that satisfies the context. The scrollbar is the case.consumer— the application decides where the role goes. Themvora declares the use as advisory and the consumer owns the judgement.
"generator" | "integration" | "consumer"
ContextRequirement
The threshold a context is held to.
decorative is not "anything goes" — it means the role must be visible and
subordinate, which is enforced as a relationship rather than a ratio. A
border is the canonical case.
ContrastRequirement | "decorative"
CoreColor
The colour roles every Themvora theme defines.
These are semantic roles, not library tokens. An adapter is responsible for expressing each one in its target library's own vocabulary — or for declaring that it does not need it.
See also: OptionalSemantic
"background" | "foreground" | "card" | "cardForeground" | "popover" | "popoverForeground" | "primary" | "primaryForeground" | "secondary" | "secondaryForeground" | "muted" | "mutedForeground" | "accent" | "accentForeground" | "destructive" | "destructiveForeground" | "success" | "successForeground" | "border" | "input" | "ring"
CreateRootLike<TRoot extends SyncFirstRenderRoot>
React's createRoot, structurally.
__type(container: Element | DocumentFragment, options?: unknown): TRoot
CVDType
The type of color vision deficiency (CVD) to simulate.
"protanopia" | "deuteranopia" | "tritanopia" | "achromatopsia"
DiagnosticSink
A destination for rendered diagnostics.
__type(text: string, diagnostic: ThemeDiagnostic): void
ForegroundPreference
Which ink a role prefers, when that preference is legible.
"light" | "dark"
GeneratedThemeStatus
The outcome of findGeneratedTheme.
"found"— exactly one eligible theme resolved (itsthemeis set)."missing"— no generated theme is registered."ambiguous"— more than one is registered and the active selection does not pick one out. Callers must reject this rather than guess.
"found" | "missing" | "ambiguous"
GenerationStyle
The visual languages a theme can be generated in.
"balanced" | "soft" | "vibrant" | "editorial" | "minimal" | "brand"
OptionalSemantic
Colour roles a theme may declare.
These are capabilities rather than contract. A theme that omits them is
complete; an adapter that needs one declares it in its optional list and
must degrade gracefully when it is absent — by deriving it, or by omitting the
library token entirely. Fabricating a value no consumer reads is worse than
omitting it, because it looks like support.
"warning" | "warningForeground" | "info" | "infoForeground" | "error" | "errorForeground"
PrePaintScrollbarOptions
Phase 1 — Bootstrap: hide native scrollbar before first paint.
This is a tiny, dependency-free, blocking <script> that runs before
React. It does ONE thing: inject a <style> and add tv-scrollbar
to <html> so the native scrollbar is never painted.
No DOM creation. No observers. No listeners. No React. No rAF.
Executes in under 1 ms.
The overlay (ThemeScrollbar) handles everything else: measure, draw,
animate, drag, hover, physics. When the overlay has been painted once,
it adds tv-scrollbar-ready to <html> — enabling CSS fade-in.
Architecture:
Phase 1 — Bootstrap (this module) └─ hide native scrollbar └─ add tv-scrollbar
Phase 2 — ThemeScrollbar (React / Web / Angular) └─ create overlay └─ measure └─ attach listeners (scroll, resize, pointer, wheel, MutationObserver)
Phase 3 — Ready └─ tv-scrollbar-ready └─ overlay fades in via CSS
Next.js (@themvora/next) server-renders the tv-scrollbar class on
<html> and inlines createPrePaintScrollbarCSS() as a <style> in
<head> when the scrollbar prop is set — so the native bar is hidden
from the very first paint AND React hydrates without a class mismatch.
Emitting createPrePaintScrollbarScript() yourself is only needed when
you're not on @themvora/next (no SSR of the class).
void
PresetFamily
The name of a preset theme family.
"neutral" | "oat" | "berry" | "mint" | "citrus" | "cocoa" | "plum" | "iris" | "sky" | "graphite"
PresetKind
Whether a recipe is a curated default or a brand-inspired starting point.
"default" | "brand"
PresetOverrides
Per-family, per-mode token overrides for the preset theme set.
Partial<Record<PresetFamily, Partial<Record<PresetVariant, PresetVariantOverride>>>>
PresetThemeName
The full name of a preset theme, e.g. "oat-light".
${unknown}${unknown}
PresetVariant
The color mode of a preset theme.
"light" | "dark"
ProvidedThemeProvenance
Provenance a theme definition declares about itself.
Only markers the library itself writes are read — meta.generation.kind for
generator output and a pack:<name> tag for an installed theme pack. Nothing
is inferred from a theme's name, family or colours: a theme called
mint-light is not thereby a preset.
See also: ProvidedThemeFamily.provenance
{ algorithm: string; kind: "generated" } | { kind: "pack"; pack: string }
RegistryFailureReason
Why a registry could not be read.
"not-a-registry" | "unsupported-construct" | "invalid-theme"
RegistryLoadResult
The outcome of reading a registry.
RegistryLoadSuccess | RegistryLoadFailure
ScopedThemeSelection
A scoped theme selection. Either an exact theme name (or family name), or an
explicit family + mode pair. Provided as a string for convenience — every
framework wrapper accepts it.
string | { name: string } | { family: string; mode?: ThemeMode }
ScrollbarArrowDir
Direction of a single arrow button on an axis strip.
"up" | "down" | "left" | "right"
ScrollbarAxis
Scrollbar overlay engine — public options, runtime types and per-host runtime state.
The philosophy: the browser always performs the scrolling. This module only renders a theme-aware, animated overlay that represents the scrollbar. It never replaces or moves native scrolling — it only synchronizes with it.
"vertical" | "horizontal"
ScrollbarFlatOptions
Flat options as the adapters forward them.
Every key is optional AND may be explicitly undefined (adapters pass their
raw props straight through), so exactOptionalPropertyTypes does not force
every call site to strip undefined keys by hand.
{ [K in keyof OverlayScrollbarOptions]: OverlayScrollbarOptions[K] }
ScrollbarOffset
The rail offset: one inset for every side, or per-side values.
number | ScrollbarOffsetSides
SemanticRole
A status role, independent of how any library spells it.
This is the intent: "this surface communicates a warning". How that becomes
--warning (shadcn), --alert-warning (Bootstrap), colorScheme.warning
(MUI) or nothing at all is the adapter's decision, not the theme's.
"success" | "warning" | "info" | "error"
ThemeBootstrapConfig<T extends ThemeDefinition>
The projection of ThemvoraConfig that crosses to the browser.
See also: toBootstrapConfig
Pick<ThemvoraConfig<T>, "themes" | "defaultTheme" | "initialMode" | "initialFamily" | "storageKey" | "prefix" | "transition" | "scrollbar">
Two consumers read this one object, and it has to satisfy both:
- the pre-paint bootstrap, which runs before any application code and can only resolve a selection from a registry, a fallback and a persisted key;
- the client runtime, which is built from this global by
resolveRuntimeOptionsand therefore sees only what is here.
The second consumer is the reason this is not simply "the bootstrap subset".
When a runtime option was left out, the browser runtime silently used its
default instead — theme.config.ts could declare transition: { enabled: false } and the page would still run a document.startViewTransition on
every theme change. That is not a cosmetic difference: a view transition
applies the document swap in a later task, so a consumer that renders from
the theme store painted the new theme one frame before the document had it.
So every serializable runtime option belongs here. What cannot cross is
excluded explicitly rather than by omission: plugins and adapters hold
functions, and persistence is a live adapter object.
ThemeChangeSource
The origin of a theme change, used to attribute debug events.
"user" | "system" | "persistence" | "broadcast" | "update" | "init"
ThemeDefinitionOrigin
Which canonical API produced a theme.
"definition" | "generated" | "catalog"
ThemeDiagnosticCode
A stable, machine-readable identifier for a Themvora diagnostic.
Codes are part of the public contract: they are what tests assert on and what tooling can filter by. The human-readable message is deliberately not — it may be reworded at any time.
Naming is TV_<DOMAIN>_<CONDITION>. Codes are added only alongside the
diagnostic that actually emits them; this union is never pre-populated with
speculative entries.
See also: ThemeDiagnostic
"TV_MODE_INVALID" | "TV_THEME_TOKEN_MISSING" | "TV_THEME_FAMILY_UNKNOWN" | "TV_THEME_OVERRIDE_UNRESOLVED" | "TV_THEME_NEUTRAL_FALLBACK" | "TV_THEME_TOKEN_INVALID" | "TV_A11Y_CONTRAST_VIOLATION" | "TV_SCHEDULE_THEME_UNRESOLVED" | "TV_CONFIG_OPTION_INVALID" | "TV_SCROLLBAR_OPTION_INVALID" | "TV_PLUGIN_DESTROY_FAILED" | "TV_SYNC_FAILED" | "TV_GENERATION_INVALID_SEED" | "TV_GENERATION_CONTRAST_REPAIR" | "TV_GENERATION_ROLE_COLLISION" | "TV_GENERATION_CONSTRAINT_UNSATISFIED" | "TV_GENERATION_THEME_NOT_FOUND" | "TV_GENERATION_THEME_AMBIGUOUS" | "TV_DIFF_UNRESOLVED_EXTENDS" | "TV_DIFF_UNRESOLVED_SYSTEM"
ThemeDiagnosticLevel
Severity of a Themvora diagnostic.
The level is a deliberate decision per diagnostic, not a default. It records what the caller is expected to do about it:
"error"— continuing would produce incorrect state."warning"— recoverable, but the caller very likely made a mistake."deprecation"— still supported, but scheduled to be removed."info"— useful context; never indicates a problem.
See also: ThemeDiagnostic
"error" | "warning" | "deprecation" | "info"
ThemeFamilies<T extends readonly ThemeDefinition[]>
Extract the literal theme-family union from a tuple of theme definitions.
When themes are defined with as const, autocomplete shows the available
families in setFamily() / initialFamily:
const themes = [
{ name: "mint-light", meta: { family: "mint", mode: "light" }, tokens: {} },
{ name: "mint-dark", meta: { family: "mint", mode: "dark" }, tokens: {} },
] as const;
// ThemeFamilies<typeof themes> → "mint"FamilyOf<T[number]> extends never ? string : FamilyOf<T[number]>
ThemeFamilyOf<T extends ThemeDefinition>
The literal family union of a single theme definition type.
ThemeFamilies below does this for a tuple; the provider's selection props
are typed against the element type, so they need the same derivation one level
down. Resolves to string when the definition does not state a literal family
(a ThemeDefinition[] variable, a generated catalog), which keeps the
dynamic-input path working.
[T["meta"] extends { family?: infer F } ? F extends string ? F : never : never] extends [never] ? string : T["meta"] extends { family?: infer F } ? F extends string ? F : string : string
ThemeIdentifier<T extends ThemeDefinition>
Every way a caller can name a provided theme.
A variant name ("cocoa-dark") or a family name ("cocoa") — the two
forms resolveThemeReference accepts. Derived from the theme definitions
the caller passes, so a statically known collection autocompletes both; a
dynamically built one widens to string rather than becoming unusable.
T["name"] | ThemeFamilyOf<T>
const themes = [
{ name: "oat-light", meta: { family: "oat", mode: "light" }, tokens: {} },
{ name: "cocoa-dark", meta: { family: "cocoa", mode: "dark" }, tokens: {} },
] as const;
// ThemeIdentifier<typeof themes[number]>
// = "oat-light" | "cocoa-dark" | "oat" | "cocoa"ThemeLifecycleEventName
Names of the lifecycle events exposed by ThemeLifecycle.
keyof ThemeLifecycleEventMap
ThemeMode
The color-mode dimension of a theme selection.
"light"and"dark"are explicit modes."system"follows the visitor'sprefers-color-schemepreference and resolves to"light"or"dark"at selection time.
"light" | "dark" | "system"
ThemeModes<T extends readonly ThemeDefinition[]>
Extract the literal theme-mode union from a tuple of theme definitions.
With as const, ThemeModes<typeof themes> → "light" | "dark".
ModeOf<T[number]> extends never ? ThemeMode : ModeOf<T[number]>
ThemeName
Stable theme identifier used for selection and lookup.
Any string is accepted; use a readable family-oriented name such as
"mint-light" or "dark".
string
ThemeOverride<Name extends string>
An explicit theme override.
Three equivalent ways to name the same thing:
- a variant (
"mint-dark") applies exactly that definition, - a family (
"mint") applies the variant the provider resolves for the mode already in effect, - a family/mode object (
{ family: "mint", mode: "dark" }) states both.
All three are resolved against the provider's own registry through resolveThemeReference, so an override cannot name a theme the provider does not have, and the family form cannot pick "whichever variant came first".
See also: resolveThemeOverride, themeOverrideKey
Name | ThemeOverrideSelection
// `themes` is the registry the provider was given.
const themes = getBuiltInThemes();
<ThemeProvider themes={themes} themeOverride="mint-dark">{children}</ThemeProvider>
<ThemeProvider themes={themes} themeOverride="mint">{children}</ThemeProvider>
<ThemeProvider themes={themes} themeOverride={{ family: "mint" }}>{children}</ThemeProvider>ThemePack<T extends ThemeDefinition>
A named collection of theme definitions installable as a group.
Themes installed through use receive a pack:<name> tag and replace
any existing theme with the same name.
void
ThemeScheduleStatus
Whether the schedule is driving theme selection right now. "active"
means the schedule is enabled and applying its light/dark selection;
"disabled" means it has been turned off (e.g. via schedule.disable()).
"active" | "disabled"
ThemeScheduleStore<T extends ThemeDefinition>
The store surface createThemeSchedule needs.
Deliberately narrower than ThemeStore: the runtime hands the schedule a
handle whose set routes through the selection controller
(applyAutomaticTheme) instead of writing the store directly, so a
transition updates the effective mode and cannot be overwritten by the OS
binding. A plain ThemeStore still satisfies this shape, so calling the
factory directly keeps working unchanged.
Pick<ThemeStore<T>, "get" | "set" | "subscribe">
ThemeTokenChangeStatus
How one token path differs between the two sides.
"added" | "removed" | "changed" | "unchanged"
TimeZoneLocation
latitude, longitude tuple.
[latitude: number, longitude: number]
TokenGroup
The name of a token group that can be emitted as CSS custom properties.
Derived from TOKEN_GROUPS so the type and the runtime order can never disagree.
typeof TOKEN_GROUPS[number]
TransitionPreset
Named or explicit transition property sets.
"smooth": full curated color set (colors, borders, radii, shadows)."subtle": reduced color set."instant": onlyopacity."custom": reserved for explicitproperties.string[]: explicit property list.
"smooth" | "subtle" | "instant" | "custom" | string[]
ValidationLevel
The validation levels, in escalating order.
"structural" | "semantic" | "contrast" | "visual" | "accessibility"
Variables
ACTION_PROMINENCE_FLOOR
The non-text floor an action fill is held to against the canvas.
3
ANIMATED_GROUP_KEYS
Token-category → CSS-property classification.
This is the single source of truth for "which token group maps to which CSS property," so the Transition Planner builds transitions from a diff without hardcoding property lists in multiple places.
colors intentionally maps to nothing here: theme colors flow through
@property-registered custom properties on :root, so the whole
var(--theme-color-*) graph animates by inheritance — no per-element work.
Every other group is animated on the scanned elements that use it.
readonly ["colors", "radius", "spacing", "typography", "shadows", "borders", "transforms", "opacity"]
BRAND_PRESET_DISCLAIMER
The canonical brand disclaimer.
Exported so every surface that shows a brand preset — the docs pages, the README, a future gallery — states the same thing in the same words. A disclaimer that is paraphrased per page is a disclaimer that eventually contradicts itself.
"These presets are brand-inspired examples for Themvora. They are not official brand themes, and they do not imply endorsement or affiliation."
CONTEXT_RESTRICTIONS
The declared restrictions.
These are not failures — they are the design system saying what it means. A brand colour is allowed to be vivid precisely because nobody promised it would work as a paragraph.
readonly ContextRestriction[]
CORE_COLORS
Every CoreColor, as a runtime list.
readonly CoreColor[]
CSS_DARK_SELECTOR
The selector a pair's dark half is emitted under.
Matches the convention the CLI's export command has always written, and the
one themvora init uses in the generated stylesheet: an explicit class and a
data-theme attribute, so a host can opt in with either.
".dark, [data-theme="dark"]"
CSS_ROOT_SELECTOR
The selector a single theme, or a pair's light half, is emitted under.
":root"
default
NuxtModule<ModuleOptions>
DEFAULT_SCHEDULED_DARK_THEME
The default neutral dark theme name used when darkTheme is omitted and
no family counterpart can be derived.
"dark"
DEFAULT_SCHEDULED_LIGHT_THEME
The default neutral theme names used when lightTheme/darkTheme are
omitted and no family counterpart can be derived.
"light"
DEFAULT_THEME_TRANSITION
The default transition configuration applied by the runtime when transitions are enabled without explicit options.
Omit<Required<ThemeTransitionOptions>, "preset"> & Partial<Pick<ThemeTransitionOptions, "preset">>
DEFAULT_TIMEZONE_LOCATION
Fallback used when nothing else can be resolved (New York).
TimeZoneLocation
DEFAULT_TRANSITION_PRESET
The transition preset used when ThemeTransitionOptions.preset is
omitted.
TransitionPreset
EMPTY_THEME_DIFF
A ThemeDiff with every group set to false, representing "nothing
changed". Used as the identity/empty diff so downstream stages can short-
circuit when no token group differs between two themes.
ThemeDiff
EMPTY_THEME_SCHEDULE_STATE
The default, disabled ThemeScheduleState snapshot. Used as the initial state before a schedule resolves its location and themes.
ThemeScheduleState
FOREGROUND_PREFERENCE
The preferred foreground for each role that has one.
Only action and emphasis surfaces appear here, and that is the whole point of the list being short. A preference is a statement about what the surface is for: a strong action fill wants light ink because that is what makes it read as an action rather than a disabled control.
Reading inks are deliberately absent. foreground, mutedForeground,
cardForeground and secondaryForeground sit on quiet surfaces whose
lightness flips with the mode, so the correct ink family flips with it too —
a fixed preference would be wrong in one mode. They fall through to highest
contrast, which is exactly right for a role whose only job is legibility.
(An earlier draft listed them as preferring "light"/"dark" and broke
mutedForeground/muted to 4.495:1 — the property test caught it. The rule
"don't give a reading ink a preference" is load-bearing.)
Readonly<Partial<Record<CoreColor, ForegroundPreference>>>
GENERATED_THEME_KIND
The meta.generation.kind value stamped by generateTheme.
See also: isGeneratedTheme
"generated"
GENERATION_STYLE_NAMES
Every style name, as a runtime list.
Exported publicly so the CLI and the docs can validate a --style argument
against the real set rather than re-listing it.
readonly GenerationStyle[]
GROUP_PROPERTIES
Maps each animatable token group to the CSS properties it drives.
colors maps to an empty list because theme colors flow through
@property-registered custom properties on :root and animate by
inheritance; every other group lists the concrete CSS properties animated
on the scanned elements that use them.
Record<AnimatedGroupKey, string[]>
GROUP_VAR_PREFIXES
CSS variable prefixes each token group materializes to (see themeToCSSVariables).
Record<keyof ThemeDiff, string[]>
migrations
The registered migration steps, ordered by their from version. Managed via
registerMigration and clearMigrations.
MigrationStep[]
OPTIONAL_SEMANTICS
Every OptionalSemantic, as a runtime list.
readonly OptionalSemantic[]
PRE_PAINT_SCROLLBAR_CSS
The CSS that hides native scrollbars while tv-scrollbar is present on
<html>. Shared by the client bootstrap script and Next's SSR output so
both apply identical rules.
The bar is painted invisible while KEEPING its space, so the gutter that keeps content clear of the rail exists from the first frame (no load-time layout shift). Two groups:
- The PAGE / window scrollbar is collapsed (
scrollbar-width: none). Its rail auto-hides, so a reserved empty strip at the window edge would read as a missing scrollbar; the standard property also overrides the WebKit sizing below, so the page never reserves one. - INNER scroll containers keep an invisible, space-occupying scrollbar. It
is sized through
::-webkit-scrollbar(not onlyscrollbar-color) because styling those pseudo-elements is what takes Chromium/Safari off OVERLAY scrollbars — so the gutter is reserved on macOS too, where the native path would take no space. The space appears only while the container actually scrolls, exactly like a nativeoverflow: autobar. - Engines without WebKit pseudo-elements (Firefox) get the same reserve through the standard properties.
string
SCROLLBAR_HIDING_STYLE_ATTR
Marker on every stylesheet that hides the native scrollbar.
Three different places can emit that CSS — this module's blocking script,
createOverlayScrollbar, and an SSR adapter (the Astro provider renders it
inline in <head>). A stylesheet is only removable if a teardown can find
it, and an id alone cannot: the SSR output has no id, and an id is a single
slot. So the marker is the contract, and the id is just a fast path.
"data-themvora-scrollbar-hiding"
SCROLLBAR_HIDING_STYLE_ID
id of the stylesheet the client-side bootstrap injects.
Kept for compatibility — a teardown must find the stylesheet whoever wrote it, so restoreNativeScrollbar looks for the marker attribute below as well, and that is the one every producer sets.
"tv-scrollbar-style"
SEMANTIC_CONTEXTS
Every context the system declares.
The required set is the invariant: a generated theme is safe for every
semantic usage Themvora's own components promise to support. The advisory
set is the honest inventory of uses that exist in the wild but are not
guaranteed — chiefly "a brand colour used as reading text on the canvas".
readonly SemanticContext[]
SEMANTIC_ROLE_GROUPS
The canonical role vocabulary, grouped by intent.
warning and info appear under states as optional — the grouping is
the same either way, but the contract is not.
readonly SemanticRoleGroup[]
ThemeInspector
Vue component that renders the framework-agnostic Theme Inspector.
Renders a <themvora-inspector> custom element (defined on mount) that
shows a floating toggle opening a panel inspecting the active theme —
identity, selection, tokens, and resolved CSS variables. Can be registered
globally via app.use(ThemeInspector).
See also: ThemeInspectorProps, useTheme
ThemeInspector(args...: any[]): CreateComponentPublicInstanceWithMixins<Readonly<ExtractPropTypes<{ bottom: { default: undefined; required: false; type: NumberConstructor }; right: { default: undefined; required: false; type: NumberConstructor }; size: { default: undefined; required: false; type: NumberConstructor }; zIndex: { default: undefined; required: false; type: NumberConstructor } }>> & Readonly<object>, __type(): VNode<RendererNode, RendererElement, { [key: string]: any }>, object, object, object, ComponentOptionsMixin, ComponentOptionsMixin, object, PublicProps, { bottom: number; right: number; size: number; zIndex: number }, true, object, object, GlobalComponents, GlobalDirectives, string, object, any, ComponentProvideOptions, { B: object; C: object; D: object; Defaults: object; M: object; P: object }, Readonly<ExtractPropTypes<{ bottom: { default: undefined; required: false; type: NumberConstructor }; right: { default: undefined; required: false; type: NumberConstructor }; size: { default: undefined; required: false; type: NumberConstructor }; zIndex: { default: undefined; required: false; type: NumberConstructor } }>> & Readonly<object>, __type(): VNode<RendererNode, RendererElement, { [key: string]: any }>, object, object, object, { bottom: number; right: number; size: number; zIndex: number }> { } & ComponentOptionsBase & VNodeProps & AllowedComponentProps & ComponentCustomProps & { install: void }
ThemeProvider
Vue component that provides a Themvora runtime to its subtree and applies the active theme to the DOM.
Renders only its default slot (no wrapper element). When no runtime prop
is given, it creates and owns a runtime from the other props, injects a
blocking zero-flash bootstrap script, and binds DOM/CSS variables on mount.
The owned runtime is destroyed on unmount. Can be registered globally via
app.use(ThemeProvider).
See also: ThemeProviderProps, useThemeRuntime, ThemeScope
ThemeProvider(args...: any[]): CreateComponentPublicInstanceWithMixins<Readonly<{ broadcast?: any; cssVariables?: false | CSSVariablesOptions; defaultTheme?: string; dom?: false | DOMBindingOptions; initialFamily?: string; initialMode?: ThemeMode; persistence?: any; readPersistenceOnInit?: boolean; runtime?: ThemeRuntime<any>; scheduled?: false | ScheduledThemeOptions; themeOverride?: ThemeOverride<string>; themes?: ThemeDefinition[]; transition?: boolean | ThemeTransitionOptions; view?: Window } { [x: string]: any }> & Readonly<object>, __type(): VNode<RendererNode, RendererElement, { [key: string]: any }>[] | undefined, object, object, object, ComponentOptionsMixin, ComponentOptionsMixin, object, PublicProps, { cssVariables: boolean | Record<string, any>; dom: boolean | Record<string, any>; initial: Record<string, any>; readPersistenceOnInit: boolean; runtime: Record<string, any>; scheduled: boolean | Record<string, any>; themeOverride: string | Record<string, any>; transition: boolean | Record<string, any> }, true, object, object, GlobalComponents, GlobalDirectives, string, object, any, ComponentProvideOptions, { B: object; C: object; D: object; Defaults: object; M: object; P: object }, Readonly<{ broadcast?: any; cssVariables?: false | CSSVariablesOptions; defaultTheme?: string; dom?: false | DOMBindingOptions; initialFamily?: string; initialMode?: ThemeMode; persistence?: any; readPersistenceOnInit?: boolean; runtime?: ThemeRuntime<any>; scheduled?: false | ScheduledThemeOptions; themeOverride?: ThemeOverride<string>; themes?: ThemeDefinition[]; transition?: boolean | ThemeTransitionOptions; view?: Window } { [x: string]: any }> & Readonly<object>, __type(): VNode<RendererNode, RendererElement, { [key: string]: any }>[] | undefined, object, object, object, { cssVariables: boolean | Record<string, any>; dom: boolean | Record<string, any>; initial: Record<string, any>; readPersistenceOnInit: boolean; runtime: Record<string, any>; scheduled: boolean | Record<string, any>; themeOverride: string | Record<string, any>; transition: boolean | Record<string, any> }> { } & ComponentOptionsBase & VNodeProps & AllowedComponentProps & ComponentCustomProps & { install: void }
ThemeScope
Vue component that applies a scoped theme to its subtree.
Renders a div wrapper carrying a data-v-tv-scope attribute and applies
the resolved theme's CSS variables to that element, overriding the
provider's selection for the subtree. Supports an exact theme, a theme
family, local theme definitions, and per-scope transitions. Can be
registered globally via app.use(ThemeScope).
See also: ThemeScopeProps, useTheme
ThemeScope(args...: any[]): CreateComponentPublicInstanceWithMixins<Readonly<ExtractPropTypes<{ family: { default: undefined; required: false; type: StringConstructor }; mode: { default: undefined; required: false; type: PropType<ThemeMode> }; theme: { default: undefined; required: false; type: StringConstructor }; themes: { default: undefined; required: false; type: PropType<readonly ...[]> }; transition: { default: undefined; type: PropType<boolean | ThemeTransitionOptions> } }>> & Readonly<object>, __type(): VNode<RendererNode, RendererElement, { [key: string]: any }>, object, object, object, ComponentOptionsMixin, ComponentOptionsMixin, object, PublicProps, { family: string; mode: ThemeMode; theme: string; themes: readonly ThemeDefinition<string>[]; transition: boolean | ThemeTransitionOptions }, true, object, any, GlobalComponents, GlobalDirectives, string, object, any, ComponentProvideOptions, { B: object; C: object; D: object; Defaults: object; M: object; P: object }, Readonly<ExtractPropTypes<{ family: { default: undefined; required: false; type: StringConstructor }; mode: { default: undefined; required: false; type: PropType<ThemeMode> }; theme: { default: undefined; required: false; type: StringConstructor }; themes: { default: undefined; required: false; type: PropType<readonly ...[]> }; transition: { default: undefined; type: PropType<boolean | ThemeTransitionOptions> } }>> & Readonly<object>, __type(): VNode<RendererNode, RendererElement, { [key: string]: any }>, object, object, object, { family: string; mode: ThemeMode; theme: string; themes: readonly ThemeDefinition<string>[]; transition: boolean | ThemeTransitionOptions }> { } & ComponentOptionsBase & VNodeProps & AllowedComponentProps & ComponentCustomProps & { install: void }
ThemeScrollbar
Vue component that replaces the native scrollbar with a themed overlay scrollbar.
Renders nothing (returns null) and instead installs an overlay scrollbar
on the target element (see ThemeScrollbarProps.tag) once mounted.
Injects the pre-paint hiding CSS synchronously during setup so the native
bar never flashes. Can be registered globally via app.use(ThemeScrollbar).
See also: ThemeScrollbarProps, ThemeProvider
ThemeScrollbar(args...: any[]): CreateComponentPublicInstanceWithMixins<Readonly<{ appearance?: ScrollbarAppearanceOptions; behavior?: ScrollbarBehaviorOptions; icons?: ScrollbarIconOptions<string>; scope?: ScrollbarScopeOptions; tag?: string }> & Readonly<object>, __type(): null, object, object, object, ComponentOptionsMixin, ComponentOptionsMixin, object, PublicProps, { appearance: Record<string, any>; behavior: Record<string, any>; icons: Record<string, any>; scope: Record<string, any> }, true, object, object, GlobalComponents, GlobalDirectives, string, object, any, ComponentProvideOptions, { B: object; C: object; D: object; Defaults: object; M: object; P: object }, Readonly<{ appearance?: ScrollbarAppearanceOptions; behavior?: ScrollbarBehaviorOptions; icons?: ScrollbarIconOptions<string>; scope?: ScrollbarScopeOptions; tag?: string }> & Readonly<object>, __type(): null, object, object, object, { appearance: Record<string, any>; behavior: Record<string, any>; icons: Record<string, any>; scope: Record<string, any> }> { } & ComponentOptionsBase & VNodeProps & AllowedComponentProps & ComponentCustomProps & { install: void }
ThemeSymbol
Vue InjectionKey used to provide and inject the active Themvora runtime.
See also: provideThemeRuntime, useThemeRuntime
InjectionKey<ThemeRuntime<any>>
themvoraCookieNames
Cookie contract shared between the server resolver, the client persistence
adapter and the blocking bootstrap script. Same names as @themvora/next:
theme-name → exact resolved theme theme-family → selected family theme-mode → selected mode (light | dark | system) theme-fingerprint→ theme-config fingerprint (stale cookies are rejected)
See also: parseCookieHeader
{ family: "theme-family"; fingerprint: "theme-fingerprint"; mode: "theme-mode"; name: "theme-name" }
TOKEN_GROUPS
Every token group that can be emitted as CSS custom properties, in the canonical order groups are emitted.
The order is part of the contract, not an accident of declaration: anything that renders or compares token groups (the CSS emitter, the theme diff) reads it from here, so a group cannot appear in one order in one place and a different order in another.
See also: TokenGroup
readonly ["colors", "spacing", "radius", "shadows", "borderWidths", "zIndex", "breakpoints", "typography", "code"]
TRANSITION_PRESETS
Built-in property lists for the named transition presets.
Record<string, string[]>
Related docs
- Families & Modes — A selection is a family (which palette) plus a mode (light/dark/system); every framework exposes the same read/write surface for it.
- Theme Discovery & Overrides — A provider exposes exactly the themes it was given — grouped by family, with variants and resolved tokens — and accepts an explicit one-shot themeOverride that outranks a saved selection.
- Runtime — One runtime per app owns the store, selection, registry, history, lifecycle and adapters; every framework binding is a thin view over it.
- ThemeScope — Apply a different family/mode (or a local theme definition) to a subtree, with scoped CSS variables and pre-paint support.
- Persistence — Persist the selection across reloads and requests, with fingerprint validation, storage adapters and theme migrations.
- Zero-flash bootstrap — Paint the correct theme on the first frame: a blocking script plus server-resolved initial state, with a Vite plugin for SPA builds.
- Nuxt — the framework integration