Skip to content

Prior art: tokens and theming

Author: Shibin Das (d34dman)Last updated

Draft

This page covers token formats, tiers, naming and layering, and the CSS that lets several design systems share one page. For each item it gives what the work is and what the module takes from it. For how this fits the wider prior art, see the overview.

Checked against sources on 2026-10-04. Refresh versions and dates before quoting.

How to read the verdicts: adopt means use it as it is; adapt means take the idea and change its shape.

Formats and layering

W3C DTCG Format 2025.10 · adopt

The first stable design-token format, a W3C Community Group final report published on 2025-10-28 alongside the Color and Resolver modules. Tokens carry $value, $type, $description, $deprecated and $extensions. The format supports aliases ({group.token}), nested groups with $extends, and colors as objects with an explicit color space. Token and group names must not contain ., { or }.

For the module: the file format for contract declarations and theme values. Drupal-specific data goes under $extensions.org.drupal.*.

Format spec · designtokens.org

DTCG Resolver Module 2025.10 · adopt

A .resolver.json file declares token sets, modifiers (theme, brand, mode) and a resolution order. Given an input such as {theme: dark}, it returns one flat token set, without a combinatorial explosion of files.

For the module: the target layering model: contract, then theme, then project. The Resolver doesn't track provenance, so the module adds a from field per value. (v0 uses its own ordered layer list, and already records provenance.)

Resolver spec

WordPress theme.json · adapt

Presets become --wp--preset--* variables. Values merge in layers: core, then theme, then child theme, then the user's Global Styles, which are stored in the database and edited in a UI.

For the module: take the layered origins, the parseable variable names and the user layer. Don't let themes choose preset names: patterns and plugins break when the theme changes.

Global settings and styles · Child themes

Style Dictionary, Tokens Studio, Figma Variables · adapt

Style Dictionary is the common build pipeline. It has supported DTCG since v4, with partial 2025.10 support (color in 5.3, dimension in 5.4); it doesn't support the Resolver module yet (#1590). Tokens Studio builds themes from combinations of token sets. Figma Variables have collections and modes, extended collections for brands (Enterprise plan), and native DTCG import and export since November 2025.

For the module: optional tooling. Drupal has to work without Node, so the module keeps a small PHP resolver.

Style Dictionary DTCG · Style Dictionary #1590 · Tokens Studio themes

Tiers and naming

Material 3, Fluent 2, Spectrum tiers · adopt

Tokens come in tiers. Material uses reference (raw palette), system (roles such as primary or surface) and component tokens; Fluent 2 uses global and alias tokens. Fluent's alias tokens include rest, hover and pressed states for light and dark. Spectrum publishes a draft machine-readable design data spec.

For the module: only the semantic (system or alias) tier is public contract. Primitives stay private to each theme, and component tokens belong to pattern specs.

Material theming · Fluent tokens · Spectrum spec

Shopify Polaris token naming · adopt

Semantic names follow a group-element-role-prominence-state grammar, for example --p-color-bg-surface-hover. Polaris React is now deprecated in favour of Polaris web components, and the token packages were last published in March 2025.

For the module: the same grammar for contract names, with states as suffixes, cited as a historical source.

Token package (archived repository) · Color tokens (archived page)

GNOME libadwaita CSS variables · adopt

A small platform contract of background and foreground pairs (window, view, card, accent, destructive, success, warning, error and more) that every app follows, now documented as CSS variables; the older named colors are discouraged. The accent color follows a system-wide preference.

For the module: bg/fg pairs as the basic unit, so contrast can be checked per pair. Its size is a good reference for v0.

CSS variables

Host-injected variables

Salesforce SLDS 2 global styling hooks · adopt

Semantic CSS variables (--slds-g-*) replace the old design tokens, and themes swap their values. Salesforce tells component authors to only reference the hooks, never redefine them, and ships SLDS Linter to enforce it. Component-level hooks (--slds-c-*) are only a developer preview in SLDS 2 (Fall '26), and Salesforce still advises components that rely on them to stay on SLDS 1 themes.

For the module: the closest analogue to this project. Keep the public contract global and semantic, and ship a linter from the start.

Styling hooks · SLDS 1 to SLDS 2

VS Code --vscode-* theme colors · adopt

VS Code exposes its theme colors (more than 750 are listed) as CSS variables in extension webviews, so extensions in any framework match any installed theme.

For the module: the consumption model: the host injects plain CSS variables. Not the size: the semantic tier stays small.

Theme color reference

Figma plugin themeColors · adopt

With themeColors: true, Figma injects --figma-color-* variables and light and dark classes into plugin UIs, and updates them live (not for externally hosted plugin UIs).

For the module: the minimal version of the idea: inject semantic variables into every island.

Plugin CSS variables

CSS for several design systems on one page

CSS @scope · adopt

Baseline (newly available) since 2026-03-24. Chrome has shipped it since 118, Safari since 17.4 and Firefox since 146; the Baseline date is when Safari 26.4 fixed a Safari 26 regression. Scope roots with lower boundaries let one design system's variables stop where another begins.

For the module: the target for nested regions such as the Navigation bar on a frontend page, for example @scope ([data-ds="admin"]) to ([data-ds]). (v0 uses attribute selectors and cascade layers.)

webstatus.dev: @scope

Cascade layers · adopt

Precedence follows the declared layer order, not specificity or load order. Unlayered styles still beat layered ones, !important reverses the order, and a shadow root's layers don't join the page's order.

For the module: declare one order up front, for example @layer ds.contract, ds.theme, ds.project, ds.user, so project overrides always win.

MDN: @layer

@property registration · adapt

Typed custom properties with initial values and inheritance control. Registrations only take effect from the main document, not from inside shadow roots; properties used in shadow DOM still follow the document's registrations.

For the module: register contract tokens once, globally. Components never register their own.

@property and Shadow DOM