Customization
GolemUI gives you three levels of customization — pick the one that fits your needs:
- CSS variable overrides — change design tokens for quick, broad adjustments.
- Class-based overrides — target specific widgets with standard CSS selectors.
- Icon customization — render the icons your design language calls for.
For full theme replacement, see Going Headless.
CSS variable overrides
Section titled “CSS variable overrides”The fastest way to customize GolemUI. Override any design token on :root or a scoped selector, and every widget that references it updates automatically.
Global overrides
Section titled “Global overrides”Set variables on :root to apply changes across your entire application:
:root { --gui-intent-primary: #8b5cf6; --gui-intent-primary-hover: #7c3aed; --gui-intent-primary-active: #6d28d9; --gui-radius-md: 8px; --gui-font-family: 'Inter', sans-serif;}Scoped overrides
Section titled “Scoped overrides”Target a specific container to limit changes to one section of your page:
.my-sidebar-form { --gui-intent-primary: #10b981; --gui-bg-surface: #f0fdf4; --gui-border-default: #a7f3d0;}<div class="my-sidebar-form"> <gui-form ...></gui-form></div>Class-based overrides
Section titled “Class-based overrides”When CSS variables alone aren’t enough, target specific BEM classes with standard CSS selectors.
Naming convention
Section titled “Naming convention”GolemUI follows the BEM naming convention consistently:
| Pattern | Example | Description |
|---|---|---|
| Block | .gui-button, .gui-form, .gui-widget | Top-level widget class |
| Element | .gui-repeater__card, .gui-repeater__add-btn | Child element within a block |
| Modifier | .gui-widget--horizontal, .gui-checkbox--left | Variant of a block or element |
| Custom element | gui-textinput, gui-select, gui-toggle | The web component tag itself |
Examples
Section titled “Examples”Target all inputs within a form:
.gui-form .gui-widget input { border-radius: 8px; border-width: 2px;}Style buttons with uppercase text:
.gui-form button.gui-button { text-transform: uppercase; letter-spacing: 0.05em;}Customize the toggle slider shape:
.gui-form gui-toggle .gui-toggle--slider { border-radius: 4px;}Add a custom background to alert notifications:
.gui-alert-notification--success { background: linear-gradient(135deg, #d1fae5, #a7f3d0);}Design tokens reference
Section titled “Design tokens reference”GolemUI defines its entire visual language through CSS custom properties on :root. Override any variable to customize the look of all widgets at once — no need to hunt through widget-specific styles.
Primitive colors
Section titled “Primitive colors”These are the base color palettes that power the entire design system. Override them to transform the overall look of every widget at once.
Neutral (Slate)
Section titled “Neutral (Slate)”| Token | Default | Preview |
|---|---|---|
--gui-color-neutral-50 | #f8fafc | |
--gui-color-neutral-100 | #f1f5f9 | |
--gui-color-neutral-200 | #e2e8f0 | |
--gui-color-neutral-300 | #cbd5e1 | |
--gui-color-neutral-400 | #94a3b8 | |
--gui-color-neutral-500 | #64748b | |
--gui-color-neutral-600 | #475569 | |
--gui-color-neutral-700 | #334155 | |
--gui-color-neutral-800 | #1e293b | |
--gui-color-neutral-900 | #0f172a | |
--gui-color-neutral-950 | #020617 |
Primary (Blue)
Section titled “Primary (Blue)”| Token | Default | Preview |
|---|---|---|
--gui-color-primary-50 | #eff6ff | |
--gui-color-primary-100 | #dbeafe | |
--gui-color-primary-200 | #bfdbfe | |
--gui-color-primary-300 | #93c5fd | |
--gui-color-primary-400 | #60a5fa | |
--gui-color-primary-500 | #3b82f6 | |
--gui-color-primary-600 | #2563eb | |
--gui-color-primary-700 | #1d4ed8 | |
--gui-color-primary-800 | #1e40af | |
--gui-color-primary-900 | #1e3a8a | |
--gui-color-primary-950 | #172554 |
Success / Info / Warning / Error
Section titled “Success / Info / Warning / Error”GolemUI ships full 50–900 scales for each status palette. Override individual stops as you need them — for example, --gui-color-success-500 and --gui-color-success-600 are the most commonly used. The semantic intent tokens below typically pull from these palettes.
| Token | Default |
|---|---|
--gui-color-white | #ffffff |
--gui-color-black | #000000 |
--gui-color-transparent | transparent |
Semantic tokens
Section titled “Semantic tokens”Semantic tokens control how widgets actually look — backgrounds, text colors, borders, and status indicators. Each token has a light and a dark value; the dark column applies when dark mode is active via data-theme="dark" or data-theme="auto", and the light column applies otherwise.
Backgrounds
Section titled “Backgrounds”| Token | Light | Dark | Usage |
|---|---|---|---|
--gui-bg-default | white | neutral-950 | Page / form background |
--gui-bg-surface | white | neutral-900 | Card and input surfaces |
--gui-bg-surface-hover | neutral-50 | neutral-800 | Hovered surfaces |
--gui-bg-surface-active | neutral-100 | neutral-700 | Active / pressed surfaces |
--gui-bg-disabled | neutral-100 | neutral-800 | Disabled elements |
--gui-bg-inverse | neutral-900 | white | Inverted backgrounds |
| Token | Light | Dark | Usage |
|---|---|---|---|
--gui-text-default | neutral-900 | neutral-50 | Primary text |
--gui-text-secondary | neutral-500 | neutral-400 | Secondary text |
--gui-text-muted | neutral-400 | neutral-500 | Muted / placeholder text |
--gui-text-inverse | white | neutral-900 | Text on inverse backgrounds |
--gui-text-disabled | neutral-400 | neutral-600 | Disabled text |
Borders
Section titled “Borders”| Token | Light | Dark | Usage |
|---|---|---|---|
--gui-border-default | neutral-300 | neutral-700 | Standard borders |
--gui-border-subtle | neutral-200 | neutral-800 | Subtle / divider borders |
--gui-border-strong | neutral-400 | neutral-600 | Emphasized borders |
--gui-border-disabled | neutral-200 | neutral-700 | Disabled borders |
--gui-border-focus | primary-500 | primary-500 | Focus ring color |
Intents
Section titled “Intents”Each status intent provides a base color, hover variant, background tint, and text color. The five intents are primary, success, info, warning, error, each with --gui-intent-<name>, --gui-intent-<name>-hover, --gui-intent-<name>-bg, and --gui-intent-<name>-text tokens (and --gui-intent-primary-active on primary):
:root { --gui-intent-primary: var(--gui-color-primary-600); --gui-intent-primary-hover: var(--gui-color-primary-700); --gui-intent-success: var(--gui-color-success-600); --gui-intent-warning: var(--gui-color-warning-500); --gui-intent-error: var(--gui-color-error-600); /* …and so on for every intent. */}In dark mode, intent backgrounds use a subtle tinted overlay that works well on dark surfaces.
Spacing
Section titled “Spacing”A rem-based spacing scale used for padding, margins, and gaps throughout all widgets.
| Token | Value | Pixels |
|---|---|---|
--gui-space-0 | 0px | 0 |
--gui-space-1 | 0.25rem | 4 |
--gui-space-2 | 0.5rem | 8 |
--gui-space-3 | 0.75rem | 12 |
--gui-space-4 | 1rem | 16 |
--gui-space-5 | 1.25rem | 20 |
--gui-space-6 | 1.5rem | 24 |
--gui-space-8 | 2rem | 32 |
--gui-space-10 | 2.5rem | 40 |
Typography
Section titled “Typography”| Token | Value | Pixels |
|---|---|---|
--gui-font-family | System sans-serif stack | — |
--gui-font-xs | 0.75rem | 12 |
--gui-font-sm | 0.875rem | 14 |
--gui-font-base | 1rem | 16 |
--gui-font-lg | 1.125rem | 18 |
--gui-font-xl | 1.25rem | 20 |
--gui-font-2xl | 1.5rem | 24 |
--gui-font-3xl | 2rem | 32 |
The default font stack is:
--gui-font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;Border radius
Section titled “Border radius”| Token | Value | Pixels |
|---|---|---|
--gui-radius-none | 0px | 0 |
--gui-radius-sm | 0.125rem | 2 |
--gui-radius-md | 0.25rem | 4 |
--gui-radius-lg | 0.5rem | 8 |
--gui-radius-xl | 0.75rem | 12 |
--gui-radius-full | 9999px | pill shape |
Shadows
Section titled “Shadows”| Token | Usage |
|---|---|
--gui-shadow-sm | Subtle elevation (0 1px 2px 0 rgb(0 0 0 / 0.05)) |
--gui-shadow-md | Medium elevation |
--gui-shadow-lg | Large elevation |
--gui-shadow-focus | Focus indicator — double-ring effect using color-mix() |
The focus shadow creates a double-ring effect — a solid inner ring matching the background and a semi-transparent outer ring in the focus color:
--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);Component-specific tokens
Section titled “Component-specific tokens”Some widgets expose dedicated tokens for fine-grained control.
Toggle
| Token | Default | Description |
|---|---|---|
--gui-toggle-width | 38px | Track width |
--gui-toggle-height | 20px | Track height |
--gui-toggle-slider-width | 16px | Thumb width |
--gui-toggle-slider-height | 16px | Thumb height |
--gui-toggle-slider-transform | 16px | Translation distance when checked |
Calendar
| Token | Default | Description |
|---|---|---|
--gui-calendar-width | 300px | Calendar container width |
--gui-calendar-change-month-button-width | 36px | Month navigation button width |
--gui-calendar-change-month-button-height | 36px | Month navigation button height |
Markdown Text
These tokens control the typography and visual style of rendered markdown content inside the Markdown Text widget.
| Token | Default | Description |
|---|---|---|
--gui-md-text-color | --gui-text-default | Base text color |
--gui-md-line-height | 1.6 | Base line height |
--gui-md-heading-color | --gui-text-default | Color for h1–h6 headings |
--gui-md-heading-weight | 600 | Font weight for headings |
--gui-md-link-color | --gui-intent-primary | Link text color |
--gui-md-link-hover-color | --gui-intent-primary-hover | Link color on hover |
--gui-md-blockquote-bg | --gui-bg-surface-hover | Blockquote background |
--gui-md-blockquote-border-color | --gui-border-strong | Blockquote left border color |
--gui-md-blockquote-color | --gui-text-secondary | Blockquote text color |
--gui-md-code-bg | --gui-bg-surface-active | Background for inline code and code blocks |
--gui-md-code-color | --gui-text-default | Text color for inline code and code blocks |
--gui-md-code-radius | --gui-radius-sm | Border radius for inline code |
--gui-md-hr-color | --gui-border-default | Color of horizontal rules (<hr>) |
Icon customization
Section titled “Icon customization”GolemUI widgets accept an icon prop and render it as a <span> element with predictable CSS hooks. GolemUI does not prescribe any specific icon library — it provides the HTML structure, and you bring the CSS to render whatever icon you want.
How icons are rendered
Section titled “How icons are rendered”When you set "icon": "save" in your form configuration, GolemUI renders:
<span class="gui-widget-icon save" data-icon="save"></span>This gives you three CSS selectors to work with:
| Selector | Description |
|---|---|
.gui-widget-icon | Always present on every icon element |
.{icon-name} (e.g. .save) | A class matching the exact icon string you passed |
[data-icon="{icon-name}"] | A data attribute with the icon string value |
GolemUI provides base positioning styles for the icon element (absolute positioning, flexbox centering, 40×40 dimensions), but the actual icon rendering is intentionally left to you. This means you can use any icon system you prefer.
Widgets with icon support
Section titled “Widgets with icon support”| Widget | Icon props |
|---|---|
| Textinput | icon |
| Password | icon, showPasswordIcon, hidePasswordIcon |
| Textarea | icon |
| Select | icon |
| Currency | icon |
| Date Input | icon |
| Range Date Input | icon |
| Calendar | icon, prevMonthIcon, nextMonthIcon |
| Button | icon, iconPosition ('left' | 'right') |
| Repeater | addButtonIcon, removeButtonIcon |
Method 1: Webfont ligatures
Section titled “Method 1: Webfont ligatures”The simplest approach. A single CSS rule targets [data-icon]::before and uses content: attr(data-icon) to render the ligature text from a webfont.
First, load the webfont in your project:
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');Then add the icon rendering rule:
.gui-widget-icon[data-icon]::before { content: attr(data-icon); font-family: 'Material Icons'; font-size: var(--gui-font-lg); font-style: normal; font-weight: normal; line-height: 1; -webkit-font-smoothing: antialiased;}With this in place, pass any Material Icons ligature name as the icon value:
{ "form": [ { "uid": "", "kind": "input", "type": "textinput", "path": "phone", "label": "Phone", "props": { "icon": "phone_callback" } }, { "uid": "", "kind": "input", "type": "textinput", "path": "email", "label": "Email", "props": { "icon": "alternate_email" } }, { "uid": "", "kind": "action", "type": "button", "label": "Save", "props": { "icon": "save" } } ]}Method 2: SVG with custom CSS class
Section titled “Method 2: SVG with custom CSS class”You can render SVG icons by targeting the icon-specific class on the <span>. Since the icon string becomes a CSS class, you can use any class-based icon system.
Pass a custom class name as the icon value:
{ "props": { "icon": "my-custom-icon" }}Then define the icon with CSS background-image:
/* Clear the default ligature text */.gui-widget-icon.my-custom-icon::before { content: '';}
/* Render an SVG icon */.gui-widget-icon.my-custom-icon { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23FFFFFF' viewBox='0 0 24 24'%3E%3Cpath d='M15.5 14h-.79l-.28-.27A6.47 6.47 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'/%3E%3C/svg%3E"); background-size: 20px 20px; background-repeat: no-repeat; background-position: center;}{ "form": [ { "uid": "", "kind": "input", "type": "textinput", "path": "search", "label": "Search", "props": { "icon": "my-custom-icon" } }, { "uid": "", "kind": "action", "type": "button", "label": "Submit" } ]}You can also use libraries like FontAwesome by passing their class names directly:
{ "props": { "icon": "fas fa-globe" }}Since the icon string is added as a CSS class, FontAwesome (or similar libraries) will pick it up automatically — as long as you’ve loaded the library’s CSS in your project.
Method 3: Images
Section titled “Method 3: Images”Use background-image with image URLs (PNG, SVG files, etc.) — the same CSS technique as inline SVGs, but referencing external files:
.gui-widget-icon.my-logo-icon::before { content: '';}
.gui-widget-icon.my-logo-icon { background-image: url('/assets/icons/github.png'); background-size: 20px 20px; background-repeat: no-repeat; background-position: center;}Then use it in your form config:
{ "form": [ { "uid": "", "kind": "input", "type": "textinput", "path": "search", "label": "Search" }, { "uid": "", "kind": "action", "type": "button", "label": "Submit", "props": { "icon": "my-logo-icon" } } ]}Mixing icon methods
Section titled “Mixing icon methods”Since each icon is independently styled via its unique CSS class, you can freely mix approaches in the same form. One field can use Material Icons ligatures, another can use an SVG, and a third can use an image.
Styling icon size and color
Section titled “Styling icon size and color”Icon size and color can be controlled through standard CSS:
/* Change icon color globally */.gui-widget-icon { color: var(--gui-intent-primary);}
/* Change icon size for webfont ligatures */.gui-widget-icon[data-icon]::before { font-size: var(--gui-font-xl);}
/* Change icon size for background-image icons */.gui-widget-icon.my-custom-icon { background-size: 24px 24px;}See also
Section titled “See also”- Theming — built-in themes (Clay), creating new themes, scoped themes.
- Going Headless — drop the courtesy layer and build a theme from scratch.
- Styling Overview — responsive scaling and RTL support.