How Arbitex's Theme System Uses CSS Custom Properties
The Arbitex brand theming system is built on a two-layer CSS custom property architecture. The separation between what can be changed and what cannot is enforced at validation time, not by convention. This post describes the architecture in enough detail that an engineer implementing a custom theme understands what the system guarantees, what it permits, and where the constraints come from.
Two Token Layers
The token system distinguishes between two categories of custom properties: locked tokens and semantic tokens.
Locked tokens are brand-identity primitives — 113 properties covering typography, spacing, border radii, and shadows. These define the structural identity of the brand. The type scale, font families (Playfair Display for display text, Outfit for body copy, DM Mono for monospace), and spacing scale all live here. Locked tokens cannot be overridden by theme files. The validation step rejects any theme that attempts to set them.
Semantic tokens are the 108 themeable properties that control how the brand identity is expressed across light and dark modes and across named themes. These are what a theme actually overrides.
The locked/semantic distinction means that typographic proportions, spacing rhythm, and shadow geometry are consistent across every theme. What changes between themes is color semantics — not structure.
Semantic Token Organization
The 108 semantic tokens are organized into functional groups:
Page-level tokens define the surface hierarchy: --color-bg (page background), --color-surface (card/panel surfaces), and --color-surface-raised (elevated surfaces like modals and dropdowns).
Text hierarchy tokens express contrast relationships in prose and UI copy: --color-ink (primary text), --color-sub (secondary), --color-muted (tertiary), and --color-subtle (disabled/placeholder).
Accent palette is an 8-token set that expresses the primary action color and its relational variants. The full set is --color-accent, --color-accent-mid, --color-accent-dk, --color-accent-lt, --color-accent-tnt, --color-accent-mut, --color-accent-on, and --color-accent-text. --color-accent-on is for text or icons rendered on top of an accent-filled surface. --color-accent-text is for accent-colored text on a neutral background — this token has a WCAG AA minimum contrast requirement against --color-bg in standard themes.
Component-level tokens map directly to UI elements: buttons, form inputs, badges, alerts, toggle controls, and navigation. These are semantic aliases that reference accent and surface tokens in the base system — overriding a page-level or accent token propagates the change through dependent component tokens automatically unless a theme explicitly pins a component token to a fixed value.
Theme Categories
Themes are grouped into four categories.
Accessibility themes are held to a WCAG AAA (7:1) contrast standard. The high-contrast theme is the primary example — it strengthens border visibility, simplifies the accent palette, and responds to the prefers-contrast: more media query. For teams building accessible products on the Arbitex platform, accessibility themes are not cosmetic variants. They are engineered to a higher contrast specification than the standard WCAG AA floor.
Preference themes are user-selectable alternatives for personal taste. The system ships several, covering cool, warm, and neutral aesthetic directions. Each preference theme supplies full light and dark mode overrides.
Seasonal and holiday themes are time-limited campaign themes — one for each meteorological season and named holidays across a range of cultural calendars. These exist as complete theme definitions that can be activated for a configured window.
Custom themes are the category that enterprise integrators use. A custom theme is a named theme that applies a client’s brand color palette within the semantic token system. The voya-financial theme is an example of a custom theme implementing a client’s primary brand color across the accent token set.
Across all categories, the system currently defines 20+ named themes. Each theme provides both light and dark mode overrides.
Theme File Structure
A theme file contains three top-level sections: meta, and within tokens, a light and dark override map.
The meta block carries the theme’s name, slug, description, category, and version. The slug is what appears in data-theme-name on the HTML element.
The tokens.light and tokens.dark maps are partial override sets. A theme only needs to specify tokens that differ from the base system. Any token not listed in a theme’s override map inherits its value from the base light or dark definition. This means a minimal theme for a client brand might only override the 8 accent palette tokens — the rest of the surface, text, and component tokens continue from the system defaults.
The schema also exposes a fontScale property for a global font size multiplier. The range is 0.85 to 1.5. The scaling is applied globally, but the system enforces a floor: --text-label must remain at or above 10px regardless of the multiplier. This prevents a legitimate accessibility concern from being introduced via an overly compressed font scale.
Additive Tokens
A theme can introduce tokens that do not exist in the base system. This is the escape hatch for implementations that need properties specific to a client brand — a secondary brand color, a custom illustration tint, or a surface token for a UI pattern that does not exist in the base component set.
Additive tokens follow a scoped naming convention: --theme-<slug>-<property>. A theme with slug voya-financial adding a custom surface token would name it --theme-voya-financial-surface-brand. The naming pattern is validated by regex (^theme-[a-z0-9]+-[a-z0-9-]+$) at schema validation time. Tokens that do not match the pattern are rejected. This prevents additive tokens from polluting the global custom property namespace or colliding with base system tokens.
Runtime Injection and FOUC Prevention
The HTML element carries data-theme="light" as the default. This is set in the static document — no JavaScript is required to render a styled page in light mode.
Dark mode and named theme preferences are persisted to localStorage. The critical implementation detail is where the restoration script runs. BaseLayout.astro includes an inline script (is:inline) in the document head that fires before first paint:
const stored = localStorage.getItem('theme');
if (stored) document.documentElement.setAttribute('data-theme', stored);
This runs synchronously before the browser lays out and paints the page. The result is that a user returning with a stored dark mode preference never sees a light-mode flash before the preference is applied. This is the standard FOUC prevention technique for CSS custom property theming systems, and the inline script placement is what makes it work. A script that ran after DOMContentLoaded would be too late — the browser would have already painted the default state.
Named theme preferences are handled via data-theme-name on the same element. The two attributes are orthogonal: data-theme controls light/dark mode, data-theme-name controls the named theme. The inline script restores both on page load.
CSS Selector Cascade
The cascade for theme overrides follows a four-level structure:
:root— base light mode tokens[data-theme="dark"]— dark mode overrides[data-theme-name="<slug>"]— named theme overrides that apply to both modes[data-theme-name="<slug>"][data-theme="light"]and[data-theme-name="<slug>"][data-theme="dark"]— named theme mode-specific overrides
Specificity increases at each level, which is how named theme rules override base definitions. Locked tokens are not targeted by any theme selector — they are defined at :root and not overridden at any selector level.
For engineers inspecting the cascade in browser DevTools: you will see locked tokens defined at :root without any competing declarations from theme selectors. Semantic tokens will show overrides at the appropriate level depending on the active data-theme and data-theme-name values.
Implementing a Custom Theme
For a team integrating a client brand, the workflow is:
- Define the 8 accent palette tokens for the client’s primary brand color in both light and dark mode variants.
- Optionally override surface and text hierarchy tokens if the brand diverges from the system defaults.
- Validate the theme file against the schema — the validator checks locked token rejection, WCAG AA contrast on
--color-accent-text, additive token naming compliance, andfontScalerange. - Register the theme slug. The
data-theme-nameattribute on the HTML element activates the named theme rules.
A minimal enterprise theme that only adjusts the accent palette will pass through approximately 8 token overrides per mode — 16 total token definitions. The remaining 100 semantic tokens inherit from the base system and require no specification.
Shadow overrides in custom themes are partially restricted: the system allows overriding the rgba tint of a shadow token, but offsets and blur values are locked. This preserves the spatial consistency of the elevation model across all themes — a card reads as “slightly raised” in every theme, not raised in one and flat in another.
What the System Enforces vs. What It Permits
The validation layer enforces: locked token immutability, WCAG AA/AAA contrast minimums by theme category, additive token naming scope, and fontScale range. These are hard rejections.
The system permits: full replacement of any semantic token in either mode, introduction of scoped additive tokens, client-brand accent palettes, and font scale adjustment within the safe range.
The design intent is that correctness properties — contrast ratios, spatial consistency, typographic identity — are guaranteed by the system. Aesthetic properties — color expression, brand personality — are fully in the hands of the theme implementer.
For teams integrating a custom enterprise theme, the schema documentation and base token reference are available at the brand guide. To see the theming system in action within the Arbitex Gateway product, book a technical demo.