Colours and tokens
Every colour Home-UI uses is a semantic token: --hui-primary, --hui-border, --hui-muted-foreground. No component hard-codes a colour, so changing one token re-themes everything that reads it — in light, in dark, and across every shadow root, because custom properties inherit through a shadow boundary. The token names follow shadcn/ui, namespaced with hui.
This is the only supported theming API. Internal selectors inside a component’s shadow root are not public and may change without notice.
The palette
Section titled “The palette”The tokens
Section titled “The tokens”Each token pairs a surface with the foreground that sits on it. Set the pair together, or a host can end up with unreadable combinations.
| Token | Light | Role |
|---|---|---|
--hui-background | oklch(1 0 0) | The page surface, when .hui-surface opts in |
--hui-foreground | oklch(0.145 0.008 326) | Body text on the background |
--hui-card / --hui-card-foreground | white / near-black | Raised surfaces and their text |
--hui-popover / --hui-popover-foreground | white / near-black | Overlay panels and their text |
--hui-primary / --hui-primary-foreground | purple / near-white | Default action fill and its label |
--hui-primary-text | oklch(0.496 0.265 301.924) | Primary-coloured text, such as the link button |
--hui-secondary / --hui-secondary-foreground | grey / near-black | Secondary action fill |
--hui-muted / --hui-muted-foreground | grey / mid-grey | Quiet fills and dimmed text |
--hui-accent / --hui-accent-foreground | grey / near-black | Hover and highlight |
--hui-destructive | oklch(0.56 0.245 27.325) | Destructive borders, text and error icon |
--hui-destructive-subtle / -foreground | pale red / red | The destructive tint and its label |
--hui-border | oklch(0.922 0.005 325.62) | Decorative hairlines |
--hui-input | oklch(0.62 0.019 323.02) | Control boundaries (needs 3:1) |
--hui-ring | oklch(0.62 0.019 323.02) | The keyboard focus ring |
The full declaration, including the shape, spacing, type, shadow and motion tokens, is in tokens.css, which you can read from the package. This page covers only colour; the other groups have their own pages.
Where the values come from
Section titled “Where the values come from”The palette is the shadcn nova style at preset b5ZcnBEttq (base colour mauve, theme purple), regenerated by command rather than transcribed:
pnpm dlx shadcn@latest preset decode b5ZcnBEttqA few values deliberately differ from that preset, each because the preset’s own value misses a WCAG threshold. The visual-style contract UI-CONTRACT-006 records each with its measurement. The notable ones:
--hui-destructiveis darkened in light mode, because nova’s value measures 3.97:1 against its own tint.--hui-destructive-subtleis an opaque token rather than an alpha fill, because an alpha fill’s ratio depends on what is behind it.--hui-primary-textis a separate token, because nova uses one value for a button fill and for link text, and its dark value measures 2.23:1 as text.
Re-theming
Section titled “Re-theming”A host overrides a token on :root, or on any ancestor of the components it wants to affect:
:root { --hui-primary: oklch(0.55 0.2 250); --hui-radius: 0.25rem;}Every component reads the token with an inline fallback — color: var(--hui-foreground, CanvasText) — so a component rendered with no token sheet at all stays legible and operable. It will not be pretty, but it will work.
Contrast
Section titled “Contrast”scripts/measure-contrast.mjs computes every required pair from the shipped sheet and exits non-zero on a miss. The measurements are tabulated in UI-CONTRACT-002. The short version: every text pair clears AA (4.5:1) in both themes, and --hui-input and --hui-ring clear the 3:1 WCAG 1.4.11 asks of a control boundary.
Two pairs are recorded rather than enforced: --hui-border is a decorative hairline, and --hui-primary is a fill, not text. Primary-coloured text is --hui-primary-text.