Skip to content
Home Theme Gallery

Dark mode

Home-UI resolves the theme in three layers, in this order:

:root { /* light values */ }
:root:not(.light) {
@media (prefers-color-scheme: dark) { /* dark values */ }
}
:root.dark { /* dark values */ }
  • No class on <html> — the operating system preference decides, and the page follows it live.
  • class="dark" — dark, whatever the system says.
  • class="light" — light, whatever the system says.

The Go host stamps the class onto <html> from a cookie or a stored user setting, before first paint. That is what avoids a flash of the wrong theme: the class is in the server’s HTML, not applied later by script.

<!doctype html>
<html class="{{ .Theme }}">
<head>
<link rel="stylesheet" href="https://home-ui.harriverse.com/dist/latest/home-ui.css" />
<script type="module" src="https://home-ui.harriverse.com/dist/latest/home-ui.js"></script>
</head>
<body class="hui-surface">

Tokens theme nothing until something applies them, and Home-UI deliberately does not style the host’s <body>: the host owns the page, and a library that claimed <body> would fight a page that has its own background.

The opt-in is one class, .hui-surface:

.hui-surface {
background-color: var(--hui-background, canvas);
color: var(--hui-foreground, canvastext);
font-family: var(--hui-font-sans, system-ui, sans-serif);
}

Without it, a host that sets class="dark" gets correctly themed components on an unthemed white page — and the ghost and link button variants become white text on white. That defect was ISS-001. Apply .hui-surface to <body>, to a wrapper, or not at all and theme the page yourself.

Components on a themed surface
Source
<hui-button>Default</hui-button>
<hui-button variant="secondary">Secondary</hui-button>
<hui-button variant="outline">Outline</hui-button>
<hui-button variant="ghost">Ghost</hui-button>
<hui-button variant="link">Link</hui-button>
<span class="hui-badge">Badge</span>
<span class="hui-badge hui-badge--destructive">Destructive</span>

Switch the site’s own theme control to watch the preview above change. Preview frames follow the catalogue’s theme switcher, so every example shows the same theme as the page around it. That is also how a host behaves: one class change re-themes every component with no JavaScript and no re-render, because they all read the same inherited custom properties.

hui-theme-toggle is the single documented exception to “the host owns the theme”. It is an optional light-DOM element that writes the class onto <html> and persists the choice in localStorage.

A host that themes server-side simply does not use it. See hui-theme-toggle.

Every preview on this site is an iframe with its own <html> element — one <link> and one module script, exactly what a host loads. That is why the tokens resolve inside it, and why a class="dark" frame behaves precisely as the contract above describes. Nothing in a preview is a reimplementation.