useKanzoTheme
Read and write the runtime theme preferences owned by KanzoThemeProvider.
Usage
import { useKanzoTheme } from "@kanzo-tech/ui";const { density, appearance, set } = useKanzoTheme();It throws outside a KanzoThemeProvider — there is no silent default,
because a component reading a theme that nothing applies is a bug, not a fallback.
The provider writes the preferences to <html> as data-* attributes and toggles .dark. This
hook is how you read that state and request a change; it never touches the DOM itself.
Preference and resolution
appearance is always light or dark: the side the person picked, or else the tenant's starting
side, or else the OS's prefers-color-scheme. The OS is a starting point and is never stored.
themeByAppearance / resolvedTheme are a preference and its resolution: an empty preference defers to whichever
theme the tenant makes default. The preference is a map keyed by side, because a theme is a
side — "which theme" without "on which side" does not name a choice.
Changing a preference
set takes a partial patch and merges it — pass one axis, not the whole object:
const { set } = useKanzoTheme();
set({ density: "compact" });
set({ appearance: "dark", density: "comfortable" });Appearance has its own setter, setAppearance, because a host theme manager (next-themes) may own
that axis. Going through set({ appearance }) would bypass the host and leave the two disagreeing.
The retired theme as a toast
When a tenant withdraws the theme a reader had chosen, the provider clears the choice and holds its
name in retiredTheme for the session, and the theme cards say so in an alert. Where the cards are
not drawn — a tenant that withholds the theme — a host that wants it said reads the same state and
toasts it once, beside its own <Toaster />. The library ships no component for it: what it would
be is the effect below under a name, and no product had called one.
API Reference
useKanzoTheme
function useKanzoTheme(): ThemeContextValue;Takes no arguments. Throws useKanzoTheme must be used within a <KanzoThemeProvider>. when no
provider is above it.
Returns
| Field | Type | What it is |
|---|---|---|
appearance | "light" | "dark" | The side being worn |
setAppearance | (next: Appearance) => void | Wears that side |
density | "default" | "compact" | "comfortable" | How big everything is, relative to the browser's font size |
themeByAppearance | Partial<Record<Appearance, string>> | Which theme this user wears on each side; {} defers to the tenant's default |
set | (patch: Partial<ThemePrefs>) => void | Merges a partial patch into the preferences and persists it |
themes | ThemeOption[] | The themes the tenant published — [], never undefined. A flat list: a brand is a theme, so there is no second level |
defaultTheme | string | The name the applied side falls back to when the preference is empty |
defaultThemeFor | (side: Appearance) => string | The same answer for either side — a tenant may publish { light, dark }, since a theme carries its own palette |
resolvedTheme | string | This side's preference, or defaultTheme |
setTheme | (theme: string, options?: { appearance?: Appearance }) => void | Choose a theme for one side — the applied one unless appearance names the other |
retiredTheme | string | null | A theme the tenant withdrew out from under this user, held for the session |
corePrefs | Record<string, ResolvedPref & { decl }> | Every core axis resolved through the tenant's policy — value, via, offered |
reset | () => void | Unsets every axis, so the tenant's starting point applies again |
sections | Record<string, Record<string, string>> | What the user chose in the sections a host registered, keyed by namespace. Opaque: the core never parses it |
sectionPrefs | Record<string, Record<string, ResolvedPref & { decl }>> | Those same choices resolved — value, via, offered — each with its declaration beside it |
setSectionPref | (namespace, values: Record<string, string | undefined>) => void | Write into one namespace. Every other namespace rides through untouched |
The preference fields are exactly ThemePrefs, so set accepts any subset of them.
sections and sectionPrefs are not the same thing
sections is the stored map — what the user picked, and nothing else. sectionPrefs is what
is applied, after a tenant's policy and the manifest's default have had their say, so the two
disagree whenever a choice is pinned or withheld. Read sectionPrefs to draw anything;
sections only to say what the user themselves chose. See
Contributing a section.
KanzoThemeProviderProps is exported, so a wrapper can take the same props without restating them.
The rest of the theme surface, for a host that builds its own controls. retiredTheme is the
theme a reader had chosen and the tenant withdrew, which the theme cards say in an alert and a host
may also toast (below). ThemeStorage is the two-method adapter the provider reads and writes through: get
returns a sparse document, because a key is absent when nobody has chosen it, not when it is at
its default. ThemeScriptOptions is what the blocking script takes, and its storageKey must match
the provider's.