@cueplusplus/tokens
The token layer under @cueplusplus/ui, for an app that needs the vocabulary by name rather than
through a component: five density rungs, fourteen font pairings, fourteen style sets and ten paint
packs, authored as DTCG source and compiled to attribute-scoped CSS custom properties.
Four of the system's five DOM axes live here, and they own strictly disjoint token sets — a page is one choice on each, so they compose as a sum rather than a product:
| axis | owns |
|---|---|
[data-density] | geometry — control heights, radii, spacing, type sizes |
[data-font] | the three type stacks a pairing names |
[data-style] | page composition — prose and UI leading, measures, band rhythm, rules and grounds, caps tracking (13 names) |
[data-paint] | the finish — rims, strokes, elevation, glow, glass, texture, edge fades (18 names and 13 inks); off until a page stamps it |
Colour is not here. The fifth axis, [data-theme], left this package: a palette is a package
of its own now (@cueplusplus/theme-<name>, and anybody else's), so there is no THEMES export,
no ThemeName, and dist/theme.css is a deprecated alias of axes.css — kept through 0.10, and
removed in the minor after. The blank palette an unstamped page paints lives in
@cueplusplus/theme-base.
Install
The @cueplusplus scope is public on npm and resolves there by default, so there is nothing
to configure and no credential to supply — it installs like any other package.
pnpm add @cueplusplus/tokens
No peers and no dependencies: this package is generated data and eight lines of JavaScript. It
also arrives as a dependency of @cueplusplus/ui, so an app that installs the components already
has it — naming it in package.json just makes the constants importable in your own code.
CI, Vercel and the token's expiry are in
docs/CONSUMING.md §1.
Quick start
An app importing @cueplusplus/ui/styles.css already has the axes as CSS; it needs this package
by name only to stop restating what it exports.
import { DENSITIES, token } from "@cueplusplus/tokens";
const ring = `1px solid ${token("focus")}`; // "1px solid var(--cue-focus)"
const labels = DENSITIES.map((rung) => [rung, rung.replace(/-/g, " ")] as const);
DENSITIES is ["ultra-compact", "compact", "normal", "large", "ultra-large"], in ladder order.
Derive a picker's labels and a stylesheet's rung list from it rather than writing either out: both
go stale silently when the ladder changes, and nothing anywhere reports it. The same holds for the
other three axes — FONTS, STYLE_SETS and PAINTS are each the full vocabulary in menu order,
and a picker built from one grows with the catalogue instead of silently missing its newest entry.
Without a bundler, the same thing in CSS is one import:
@import "@cueplusplus/tokens/axes.css";
What it ships
| subpath | what it is |
|---|---|
@cueplusplus/tokens | the four axis vocabularies — DENSITIES, FONTS, STYLE_SETS, PAINTS — with MODES and every DEFAULT_*; the contracts each axis owns (COLOR_CONTRACT, GEOMETRY_CONTRACT, FONT_TOKENS, STYLE_CONTRACT, STYLE_SET_CONTRACT, PAINT_CONTRACT, PAINT_INK_CONTRACT, PAINT_INKS); FONT_PAIRINGS and FONT_FACES; faceProperty() and token(); and a type for each |
./axes.css | the density, font, style-set and paint axes as CSS — every [data-density], [data-font], [data-style] and [data-paint] block — with no colour in them |
./tailwind.css | the Tailwind v4 @theme inline mapping layer |
./theme.css | a deprecated alias of ./axes.css: kept through 0.10, removed in the minor after |
./base.json | the same axes as data, for a theme built outside this build |
./primitives.tokens.json | the tier-1 palette a theme source aliases |
./registry/token-layer.json | the theme-independent half of the layer as a shadcn fragment — folded into a registry base item, not installable on its own |
The root entry is dist/tokens.js with dist/tokens.d.ts beside it — plain JavaScript, because
Node refuses to strip types for anything under node_modules and a .ts entry is one a
registry consumer cannot load.
Everything here is generated by build.mjs from src/**.tokens.json. Edit the sources, never
dist/.
Where the rest is
- Installing and using it from another project:
docs/CONSUMING.md - The density ladder, and what moves on each rung: https://ui.cueplusplus.com/docs/density
- The paint axis, its ten packs and what each refuses: https://ui.cueplusplus.com/docs/paint
- The fourteen pairings, and which ten your app has to deliver: https://ui.cueplusplus.com/docs/typefaces
- The
--cue-*contract and how a theme fills it: https://ui.cueplusplus.com/docs/theming - What changed in the version you have:
node_modules/@cueplusplus/tokens/CHANGELOG.md