CSS Token Hoisting #

CSS Token Hoisting is a build-time optimization that discovers which CSS custom properties (design tokens) your application actually uses, and includes only those in the protocol output. This enables host runtimes to resolve design tokens efficiently without shipping unused variables.

How It Works #

During the build process, WebUI extracts CSS custom property usages - names referenced via var(--name) - from two sources:

  1. Component CSS files - tokens are extracted when components are registered and cached in the component registry.
  2. Inline <style> tags - tokens are extracted from <style> elements in the entry HTML file and component templates.

The resulting set of tokens is sorted, deduplicated, and included in the protocol's tokens field.

What Gets Hoisted #

Only var() usages are hoisted - not custom property definitions:

/* โœ… HOISTED - usage via var() */
.button {
  color: var(--colorPrimary);           /* โ†’ "colorPrimary" */
  background: var(--bgColor);           /* โ†’ "bgColor" */
}

/* โŒ NOT hoisted - this is a definition */
:root {
  --colorPrimary: #0078d4;
}

Nested Fallbacks #

Fallback variables in var() calls are also extracted:

.card {
  /* All three tokens are extracted: "a", "b", "c" */
  color: var(--a, var(--b, var(--c)));
}

Literal fallback values (like 16px) are ignored - only variable references are extracted. Malformed var() calls fail the build instead of hoisting partial token names.

Local Definition Exclusion #

If a custom property is both defined and used in the same CSS file, it is excluded from the token set. This prevents locally-scoped variables from being hoisted:

:host {
  --internal-spacing: 8px;             /* definition */
  padding: var(--internal-spacing);     /* usage */
  color: var(--designSystemColor);      /* usage only โ†’ HOISTED */
}
/* Result: only "designSystemColor" is hoisted */

Comment Handling #

HTML and CSS comments are stripped at build time. Bindings inside HTML comments are ignored, so comments cannot be used as token placeholders. CSS legal comments are preserved only when --legal-comments inline is active. Unterminated HTML or CSS comments fail the build.

Inside <style> tags, dynamic CSS fragments are valid only when wrapped in a CSS block comment. The comment must contain exactly one handlebars expression:

<style>
  :root {
    /*{{{tokens.light}}}*/
  }
</style>

Protocol Output #

The hoisted tokens appear in the protocol's tokens field:

{
  "fragments": { ... },
  "tokens": [
    "bgColor",
    "borderRadiusSmall",
    "colorBrandBackground",
    "colorPrimary",
    "fontFamilyBase",
    "lineHeightBase400",
    "spacingHorizontalM"
  ]
}

The list is always sorted alphabetically and deduplicated across all components and inline styles.

CLI Output #

When tokens are discovered, the build command reports the count:

โœ” Registered 5 components
โœ” Parsed index.html (23 fragments)
โœ” Discovered 12 CSS tokens
โœ” Build complete (3 files written) in 42ms