Customizable schema
The customizable field on a theme is a map from dotted theme paths to field descriptors. The library renders one editor per entry inside the Settings system window, applies user overrides on top of the theme defaults, and persists them through the storage adapter.
The map
Section titled “The map”customizable: { "palette.accent": { kind: "color-from-palette", label: "Accent", options: ["#5cb6b9", "#7c66f5", "#a855f7", "#ec4899"], }, "shape.windowRadius": { kind: "range", label: "Window radius", min: 0, max: 24, step: 2, unit: "px", }, "chrome.dockPosition": { kind: "select", label: "Dock position", options: [ { value: "bottom", label: "Bottom" }, { value: "left", label: "Left" }, { value: "hidden", label: "Hidden" }, ], },}- Keys are dotted paths into
OsTheme. The library walks them to write the override. - A theme that omits
customizable(or sets it to{}) exposes no Settings panel. - Stale prefs (paths the theme later removed) are silently ignored.
Field kinds
Section titled “Field kinds”| Kind | Editor | Required fields |
|---|---|---|
color-from-palette | A row of color swatches. | options: string[] (hex / CSS colors) |
image-pick | A thumbnail grid. | options: Array<{ src: string; label: string }> |
range | A slider with a tabular-numeric readout. | min, max, step; optional unit |
select | A segmented control. | options: Array<{ value: string; label: string }> |
toggle | An iOS-style switch (role="switch"). | (none) |
Every kind also accepts label: string, description?: string, and section?: string.
Grouping with section
Section titled “Grouping with section”"palette.accent": { section: "Appearance", … },"shape.windowRadius": { section: "Appearance", … },"motion.genieDurationMs":{ section: "Motion", … },"chrome.dockPosition": { section: "Layout", … },Each section becomes a category in the Settings panel: a sidebar that the
user clicks or arrow-keys through, folding into a horizontal bar when the window
is narrow. A search field above the categories filters across every section at
once (matching a field’s label, description, or section name), so a setting is
reachable no matter which category it lives in. A field with no section
falls under “General”.
Effective tokens
Section titled “Effective tokens”defaults < declared theme < user prefsAt runtime the active theme is applyPrefs(baseTheme, prefs). The function walks each pref path, shallow-clones along the way, and writes the leaf, leaving everything else untouched. The library re-runs this on every pref change.
Reading what a theme exposes
Section titled “Reading what a theme exposes”From any component:
import { useSettings } from "@react-ui-os/desktop";
const { schema } = useSettings();const fieldsByCategory = Object.entries(schema).map(([path, def]) => ({ path, category: path.split(".")[0], ...def,}));The full hook surface is in useSettings.
See also
Section titled “See also”- Settings: the UI that renders the schema.
useSettings: the read / write hook.- Writing a theme: declaring
customizablein your own theme.