Theming
GolemUI ships with a default theme, a bundled alternative (Clay), opt-in dark mode, and a clear pattern for creating and scoping your own themes.
Loading the default theme
Section titled “Loading the default theme”The default theme is included in @golemui/gui-components/index.css. Import it once in your project’s CSS or SCSS entry point:
@import '@golemui/gui-components/index.css';That’s all that’s needed — every widget renders with the default look and the design tokens documented in Customization are available for overrides. Dark mode is opt-in; the section below covers it.
Dark mode
Section titled “Dark mode”Dark mode is opt-in, picked via a data-theme attribute on any ancestor element (most often <html> or <body>). The library never silently flips your page based on system preference — a component-library CSS import that quietly restyles a host page in dark systems is a surprise nobody wants, so you say what you want explicitly.
data-theme value | Effect |
|---|---|
| (no attribute) | Default light tokens everywhere. |
"auto" | Default theme, system-follow. Reads prefers-color-scheme — light by day, dark by night. |
"dark" | Default theme, forced dark regardless of system preference. |
"clay" | The bundled Clay theme, always light. |
"clay-auto" | Clay theme, system-follow. |
"clay-dark" | Clay theme, forced dark. |
<!-- Always light (default) --><html lang="en"> <!-- Follow the user's system preference --> <html lang="en" data-theme="auto"> <!-- Force dark for everyone, ignore system preference --> <html lang="en" data-theme="dark"></html> </html></html>The attribute can sit on <html>, <body>, or any container — the cascade decides what each form picks up. See Scoped themes below for mixing modes on the same page.
All colors, backgrounds, borders, and status indicators adjust for dark backgrounds. You can see the exact light and dark values for every token in the Customization reference.
Using the alternative Clay theme
Section titled “Using the alternative Clay theme”Clay is a warm, terracotta-inspired theme that replaces the neutral slate palette with earthy tones and uses terracotta as the primary accent color. It mirrors the base theme’s opt-in light/dark/auto split.
Loading the Clay theme:
@import '@golemui/gui-components/index.css';@import '@golemui/gui-components/themes/clay.css';Applying the theme:
<!-- Clay, always light --><div data-theme="clay"> <gui-form ...></gui-form></div>
<!-- Clay, follow the user's system preference --><div data-theme="clay-auto"> <gui-form ...></gui-form></div>
<!-- Clay, forced dark --><div data-theme="clay-dark"> <gui-form ...></gui-form></div>Creating a custom theme
Section titled “Creating a custom theme”Follow the same light/dark/auto split as the base theme and Clay — three data-theme values for one theme, so consumers can pick exactly which mode they want.
-
Choose the three theme selectors
Section titled “Choose the three theme selectors”Pick a base name (e.g.
sunset) and reserve threedata-themevalues:sunset(always light),sunset-dark(forced dark),sunset-auto(system-follow):[data-theme='sunset'],[data-theme='sunset-dark'],[data-theme='sunset-auto'] {/* light tokens shared by all three */} -
Override the tokens you need (light variant)
Section titled “Override the tokens you need (light variant)”Define the light palette on the selector list above. All three variants start here; the dark variant later only overrides what actually changes.
[data-theme='sunset'],[data-theme='sunset-dark'],[data-theme='sunset-auto'] {/* Override primitives for a warm palette */--gui-color-primary-400: #fb923c;--gui-color-primary-500: #f97316;--gui-color-primary-600: #ea580c;--gui-color-primary-700: #c2410c;--gui-color-primary-800: #9a3412;/* Override semantic tokens */--gui-intent-primary: var(--gui-color-warning-600);--gui-intent-primary-hover: var(--gui-color-warning-700);--gui-intent-primary-active: var(--gui-color-warning-800);--gui-border-focus: var(--gui-color-warning-500);/* Adjust backgrounds */--gui-bg-default: #fff7ed;--gui-bg-surface: #ffffff;/* Adjust borders */--gui-border-default: var(--gui-color-warning-300);--gui-shadow-focus:0 0 0 2px var(--gui-bg-default),0 0 0 4px color-mix(in srgb, var(--gui-border-focus) 50%, transparent);} -
Add the dark variant
Section titled “Add the dark variant”Apply dark token overrides via two selectors:
[data-theme='sunset-dark']for the forced-dark variant, and[data-theme='sunset-auto']inside aprefers-color-scheme: darkmedia query for the system-follow variant.[data-theme='sunset-dark'] {--gui-bg-default: #1c1210;--gui-bg-surface: #271a16;--gui-border-default: var(--gui-color-warning-600);--gui-intent-primary: var(--gui-color-warning-500);--gui-intent-primary-hover: var(--gui-color-warning-400);}@media (prefers-color-scheme: dark) {[data-theme='sunset-auto'] {--gui-bg-default: #1c1210;--gui-bg-surface: #271a16;--gui-border-default: var(--gui-color-warning-600);--gui-intent-primary: var(--gui-color-warning-500);--gui-intent-primary-hover: var(--gui-color-warning-400);}}If repeating the dark overrides feels noisy, factor them into a Sass
@mixin(or a PostCSS custom property block) and include it in both selectors — that’s what the base theme and Clay do internally. -
Apply the theme
Section titled “Apply the theme”Pick one of the three values when applying:
<!-- Sunset, always light --><div data-theme="sunset"><gui-form ...></gui-form></div><!-- Sunset, follow the user's system preference --><div data-theme="sunset-auto"><gui-form ...></gui-form></div><!-- Sunset, forced dark --><div data-theme="sunset-dark"><gui-form ...></gui-form></div>
Scoped themes
Section titled “Scoped themes”Because data-theme is a standard CSS attribute selector, themes can be scoped to a specific container rather than applied page-wide. The same page can host multiple themes side by side, and switching themes is just a DOM-attribute change.
Multiple themes on one page
Section titled “Multiple themes on one page”Place each data-theme on a different container:
<div data-theme="clay"> <gui-form ...></gui-form></div>
<div data-theme="sunset"> <gui-form ...></gui-form></div>Each form renders with its own theme. The CSS cascade handles everything naturally — no JavaScript needed.
Per-section overrides
Section titled “Per-section overrides”A common pattern is a default page theme with one section opted into a different look — for example, a “preview” panel that always uses the dark theme:
<body> <main> <gui-form ...></gui-form> <!-- default theme --> </main> <aside data-theme="clay"> <gui-form ...></gui-form> <!-- clay theme inside this aside --> </aside></body>Switching at runtime
Section titled “Switching at runtime”Because the theme is a DOM attribute, swapping it is a single line of JavaScript:
document.querySelector('[data-theme]').dataset.theme = 'sunset';Every widget inside that subtree updates immediately. No re-render of the form definition is needed; the CSS cascade does the work.