Skip to content

@absoluteui/theme/designer

Theme Designer engine: theme families, seed-to-role derivation, compliance assessment, and exports.

import { ... } from '@absoluteui/theme/designer';

The Theme Designer engine builds a theme family (light, dark, and high-contrast modes) from a few brand colors, assesses it against WCAG 2.2 AA, and exports it for the theme runtime. It is pure functions with no DOM access: use it in build scripts, internal tools, or a settings screen that lets tenants brand the application. Applications that only apply themes never need it. The Theming guide explains families and export formats.

How do I derive a theme from brand seed colors?

Section titled “How do I derive a theme from brand seed colors?”

Pass the seeds you have; the rest come from the defaults. Every text, border, and indicator color is solved to meet its contrast pairing in each mode, so a seed may come back adjusted (here the dark mode lightens the primary color).

import { deriveFamily } from '@absoluteui/theme/designer';
const family = deriveFamily({
name: 'acme-hr',
seeds: { primary: '#0F766E', accent: '#7C3AED' },
version: '1.2.0',
author: 'Acme HR Platform Team',
});
family.modes.light.tokens['color-primary']; // => '#0F766E'
family.modes.dark.tokens['color-primary']; // => '#5FB6AD'
family.modes.light.tokens['color-on-primary']; // => '#FFFFFF'

assessCompliance checks every mode for text and non-text contrast, focus visibility, state differentiation, target size, zoom, motion, and high contrast. compliant is true only when no required rule fails; each finding names the tokens, components, and a fix. Re-assess after every manual override.

import { assessCompliance, deriveFamily } from '@absoluteui/theme/designer';
const family = deriveFamily({ name: 'acme-hr', seeds: { primary: '#0F766E' } });
assessCompliance(family).compliant; // => true
const light = family.modes.light;
const edited = { ...family, modes: { ...family.modes, light: { ...light, tokens: { ...light.tokens, 'color-text-muted': '#B0B0B0' } } } };
const report = assessCompliance(edited);
report.compliant; // => false
const worst = report.findings[0];
[worst?.rule, worst?.measured, worst?.expected]; // => ['WCAG 2.2 1.4.3', '2.16:1', '4.5:1']
worst?.remediation; // => 'Change color-text-muted to #767676 or darker/lighter to reach 4.5:1.'

How do I apply a family at runtime without exporting it?

Section titled “How do I apply a family at runtime without exporting it?”

familyToThemes flattens the family into one theme per mode (<name>, <name>-dark, <name>-high-contrast) that registerTheme accepts. Densities, responsive values, and <name>-system need the exported theme.css.

import { configureAbsoluteUI } from '@absoluteui/core';
import { registerTheme, startThemeRuntime } from '@absoluteui/theme';
import { deriveFamily, familyToThemes } from '@absoluteui/theme/designer';
const family = deriveFamily({ name: 'acme-hr', seeds: { primary: '#0F766E' } });
familyToThemes(family).map((theme) => registerTheme(theme).name); // => ['acme-hr', 'acme-hr-dark', 'acme-hr-high-contrast']
startThemeRuntime();
configureAbsoluteUI({ common: { theme: 'acme-hr-dark' } });
getComputedStyle(document.documentElement).getPropertyValue('--aui-color-primary'); // => '#5FB6AD'

How do I export it as CSS, JSON, or a package?

Section titled “How do I export it as CSS, JSON, or a package?”

Every exporter validates the family first and is deterministic. toCss is the stylesheet to ship (all modes, <name>-system, densities, responsive values); toThemeJson is the editable source that importTheme reads back; toFontsCss is the opt-in font loader. toPackageZip bundles all of them, plus a registration module, DTCG token files, and a compliance report, as a versioned npm package.

import { deriveFamily, importTheme, packageFiles, toCss, toPackageZip, toThemeJson } from '@absoluteui/theme/designer';
const family = deriveFamily({ name: 'acme-hr', seeds: { primary: '#0F766E' }, version: '1.2.0' });
toCss(family).includes('[data-aui-theme="acme-hr-system"]'); // => true
importTheme(toThemeJson(family)).ok; // => true
const files = packageFiles(family, { packageName: '@acme/hr-theme' }).map((f) => f.path);
files.slice(0, 6); // => ['package.json', 'README.md', 'index.js', 'index.d.ts', 'theme.css', 'fonts.css']
const zip = toPackageZip(family, { packageName: '@acme/hr-theme' });
String.fromCharCode(zip[0] ?? 0, zip[1] ?? 0); // => 'PK'

In the application, import the package’s theme.css, call its registerAcmeHrTheme(), and set theme: 'acme-hr' (or acme-hr-system) in configuration.

How do I load a theme file someone uploaded?

Section titled “How do I load a theme file someone uploaded?”

Treat theme files as untrusted. importTheme enforces a size limit, known token names, and a safe CSS value grammar, migrates schema version 1 themes, and returns every problem with its JSON path instead of throwing.

import { deriveFamily, importTheme } from '@absoluteui/theme/designer';
const family = deriveFamily({ name: 'acme-hr' });
const light = family.modes.light;
const upload = JSON.stringify({ ...family, modes: { ...family.modes, light: { ...light, tokens: { ...light.tokens, 'color-bg': 'url(https://evil.test/a.png)' } } } });
const result = importTheme(upload);
result.ok; // => false
result.ok ? [] : result.errors.map((e) => e.path); // => ['modes.light.tokens.color-bg']

Exporters reject an invalid family with THEME_INVALID (names are lowercase kebab-case, versions are semantic versions). A derived family is compliant, but manual overrides can break it: never present a family whose report is not compliant as accessible, and verify rendered pages as well, because the assessment is token-level.

import { deriveFamily, toCss } from '@absoluteui/theme/designer';
toCss(deriveFamily({ name: 'Acme HR' })); // => throws THEME_INVALID
toCss(deriveFamily({ name: 'acme-hr', version: 'v2' })); // => throws THEME_INVALID

oklchToRgb

Convert to sRGB, reducing chroma until the color is inside the sRGB gamut.

function oklchToRgb(color: Oklch): RGBA;

parseOklch

function parseOklch(value: string): Oklch | null;

rgbToOklch

function rgbToOklch(c: RGBA): Oklch;

solveLightness

Move color along OKLCH lightness (keeping hue and chroma where the gamut allows) until it reaches ratio against every backdrop. direction -1 darkens, +1 lightens. Returns the first passing color, or the extreme (black/white end) when none passes.

function solveLightness(color: Oklch, backdrops: readonly RGBA[], ratio: number, direction: -1 | 1): RGBA;

toHex

const toHex: (c: RGBA) => string;

toRgba

rgba() text with the given alpha, for translucent role tokens.

const toRgba: (c: RGBA, alpha: number) => string;

Oklch

interface Oklch {
readonly l: number;
readonly c: number;
readonly h: number;
}

assessCompliance

Assess a theme family against every the specification category. Findings are sorted most urgent first.

function assessCompliance(family: ThemeFamily): ComplianceReport;

toMs

function toMs(value: string | undefined): number | null;

toPx

Length in CSS px (rem and em at a 16px root); null when the unit is not measurable.

function toPx(value: string | undefined): number | null;

categoryLabels

const categoryLabels: Readonly<Record<ComplianceCategory | 'contrast', string>>;

CategorySummary

interface CategorySummary {
readonly category: ComplianceCategory | 'contrast';
readonly label: string;
readonly passed: number;
readonly failed: number;
readonly warnings: number;
readonly notMeasurable: number;
readonly requiredFailures: number;
}

ComplianceFinding

interface ComplianceFinding {
readonly id: string;
readonly category: ComplianceCategory;
readonly rule: string;
readonly status: RuleStatus;
readonly severity: Severity;
readonly required: boolean;
readonly mode: ThemeMode | 'all';
readonly message: string;
readonly measured: string | null;
readonly expected: string | null;
readonly tokens: readonly string[];
readonly components: readonly string[];
readonly remediation: string | null;
}

ComplianceReport

interface ComplianceReport {
readonly family: string;
readonly compliant: boolean;
readonly statement: string;
readonly categories: readonly CategorySummary[];
readonly findings: readonly ComplianceFinding[];
}

ComplianceCategory

type ComplianceCategory = 'text-contrast' | 'large-text-contrast' | 'non-text-contrast' | 'focus-visibility' | 'state-differentiation' | 'target-size' | 'zoom-reflow' | 'reduced-motion' | 'high-contrast';

RuleStatus

type RuleStatus = 'pass' | 'fail' | 'warn' | 'not-measurable';

defaultFoundation

Non-color foundation tokens (typography, spacing, shape, motion) of the built-in family.

function defaultFoundation(): TokenMap;

deriveFamily

A complete family derived from seeds (no component overrides, built-in densities).

function deriveFamily(options: DeriveFamilyOptions): ThemeFamily;

deriveMode

Derive the complete token set of one mode from seeds and the (light) foundation. Dark mode deepens shadows; high contrast thickens borders and focus rings and drops shadows.

function deriveMode(seedMap: TokenMap, mode: ThemeMode, foundation?: TokenMap): TokenMap;

normalizeSeeds

Seeds from a token map, filling unknown or unparseable entries from the defaults.

function normalizeSeeds(seeds: TokenMap): ThemeSeeds;

overriddenTokens

Which tokens of a mode differ from what the seeds derive (the author’s manual overrides).

function overriddenTokens(family: ThemeFamily, mode: ThemeMode): readonly string[];

ratioOf

Contrast ratio helper for UIs (two CSS colors; null when either cannot be parsed).

function ratioOf(foreground: string, background: string): number | null;

defaultSeeds

const defaultSeeds: ThemeSeeds;

seedNames

const seedNames: readonly (keyof ThemeSeeds)[];

DeriveFamilyOptions

interface DeriveFamilyOptions {
readonly name: string;
readonly seeds?: TokenMap;
readonly foundation?: TokenMap;
readonly version?: string;
readonly description?: string;
readonly author?: string;
readonly fonts?: readonly WebFont[];
}

ThemeSeeds

interface ThemeSeeds {
readonly primary: string;
readonly secondary: string;
readonly accent: string;
readonly success: string;
readonly error: string;
readonly warning: string;
readonly info: string;
readonly background: string;
readonly surface: string;
}

componentOverrides

Component tokens set anywhere in a family, for summaries.

function componentOverrides(family: ThemeFamily): readonly {
mode: ThemeMode;
name: string;
value: string;
fallback: string;
}[];

dtcgPath

DTCG group and token name for a global token (color-text-muted -> color / text-muted).

function dtcgPath(name: string): [string, string];

packageFiles

The files of a versioned theme package, before zipping.

function packageFiles(family: ThemeFamily, options?: PackageOptions): PackageFile[];

toCss

CSS custom properties in the aui.theme cascade layer. Themes: &lt;name>, &lt;name>-dark, &lt;name>-high-contrast, and &lt;name>-system (follows the OS color scheme and contrast preference). Densities and responsive overrides are included. Web fonts are not: they load from toFontsCss(), so this file never makes a third-party request.

function toCss(family: ThemeFamily): string;

toDtcg

DTCG design tokens for one mode (Format Module 2025.10; media type application/design-tokens+json, extension .tokens.json). Component tokens that a mode does not override are exported as aliases of their global fallback. Values DTCG cannot express (for example % or calc()) are kept under $extensions.

function toDtcg(family: ThemeFamily, mode: ThemeMode): string;

toFontsCss

Opt-in web font loader: @import rules for the family’s font stylesheets, with the CSP hosts they need. Empty (comments only) when the family has no web fonts.

function toFontsCss(family: ThemeFamily): string;

toPackageZip

Versioned theme package as zip bytes; entries sit under package/, like an npm tarball.

function toPackageZip(family: ThemeFamily, options?: PackageOptions): Uint8Array;

toScss

SCSS maps: modes (tokens and component tokens), densities, responsive overrides.

function toScss(family: ThemeFamily): string;

toThemeJson

Theme JSON (schema version 2), the format importTheme() reads back.

function toThemeJson(family: ThemeFamily): string;

toTypeScript

TypeScript module: the family plus a function that registers its three themes at runtime.

function toTypeScript(family: ThemeFamily): string;

PackageFile

interface PackageFile {
readonly path: string;
readonly content: string;
}

PackageOptions

interface PackageOptions {
readonly packageName?: string;
readonly license?: string;
}

assertValidFamily

Validate a family built in memory (for example by a designer UI) before it is exported or applied. Throws a THEME_INVALID configuration error listing the issues.

function assertValidFamily(family: ThemeFamily): ThemeFamily;

importTheme

Parse and validate theme file text.

function importTheme(textInput: string): ImportResult;

importThemeValue

Validate an already-parsed value.

function importThemeValue(input: unknown): ImportResult;

MAX_IMPORT_BYTES

const MAX_IMPORT_BYTES = 1000000;

ImportIssue

interface ImportIssue {
readonly path: string;
readonly message: string;
}

ImportResult

type ImportResult = {
readonly ok: true;
readonly family: ThemeFamily;
readonly format: 'family-v2' | 'theme-v1' | 'bundle-v1';
readonly warnings: readonly string[];
} | {
readonly ok: false;
readonly errors: readonly ImportIssue[];
};

builtInFamily

The built-in Absolute Default family (light, dark, high contrast), the designer’s starting point.

function builtInFamily(): ThemeFamily;

familyToThemes

Flatten a family into schema-1 theme definitions that registerTheme() accepts.

function familyToThemes(family: ThemeFamily): ThemeDefinition[];

modeThemeName

Runtime theme name of one mode (brand, brand-dark, brand-high-contrast).

function modeThemeName(familyName: string, mode: ThemeMode): string;

resolveToken

The value a component token resolves to in a mode: its override, else its global fallback.

function resolveToken(mode: FamilyMode, name: string): string | undefined;

breakpointNames

const breakpointNames: readonly BreakpointName[];

breakpoints

Same values as the SCSS $aui-breakpoints map.

const breakpoints: Readonly<Record<BreakpointName, number>>;

componentTokenComponents

Components with component tokens, for UIs that group overrides by component.

const componentTokenComponents: readonly string[];

densityNames

const densityNames: readonly DensityName[];

FAMILY_SCHEMA_VERSION

const FAMILY_SCHEMA_VERSION = 2;

familyModes

const familyModes: readonly ThemeMode[];

RESPONSIVE_TOKEN_RE

Tokens a responsive (min-width) override may change: typography, spacing, layout widths.

const RESPONSIVE_TOKEN_RE: RegExp;

FamilyMode

interface FamilyMode {
readonly tokens: TokenMap;
readonly componentTokens: TokenMap;
}

ThemeFamily

interface ThemeFamily {
readonly schemaVersion: typeof FAMILY_SCHEMA_VERSION;
readonly name: string;
readonly version: string;
readonly description: string;
readonly author: string;
readonly seeds: TokenMap;
readonly fonts: readonly WebFont[];
readonly modes: Readonly<Record<ThemeMode, FamilyMode>>;
readonly densities: Readonly<Record<DensityName, TokenMap>>;
readonly responsive: Readonly<Partial<Record<BreakpointName, TokenMap>>>;
}

BreakpointName

type BreakpointName = 'sm' | 'md' | 'lg' | 'xl';

DensityName

type DensityName = 'compact' | 'spacious';

themeJsonSchema

function themeJsonSchema(): Record<string, unknown>;

THEME_SCHEMA_ID

const THEME_SCHEMA_ID: string;

tokenUsage

Components whose stylesheets read each token (the specification affected components).

const tokenUsage: Readonly<Record<string, readonly string[]>>;

crc32

function crc32(bytes: Uint8Array): number;

createZip

function createZip(entries: readonly ZipEntry[]): Uint8Array;

readZip

Read a stored-only zip produced by createZip (for tests and round trips).

function readZip(zip: Uint8Array): Map<string, Uint8Array>;

ZipEntry

Minimal ZIP writer (PKWARE APPNOTE 6.3.x): stored (uncompressed) entries, UTF-8 names, fixed timestamps so the same input always produces the same bytes. Enough for small theme packages without a dependency.

interface ZipEntry {
readonly path: string;
readonly content: string | Uint8Array;
}