Tokens
Design tokens and theming with tokens.create, createTheme, and color modes
Tokens are design primitives (colors, spacing, etc.) exposed as CSS custom properties. They keep your styles consistent and make theming straightforward.
Scoped token instances
The default import { tokens } from 'typestyles' is unscoped. For a package or micro-frontend that shares the page with other TypeStyles bundles, call createTokens({ scopeId }) once and reuse that instance so custom properties and theme classes do not collide:
import { createTokens } from 'typestyles';
export const tokens = createTokens({ scopeId: 'acme-ui' });
const color = tokens.create('color', { primary: '#0066ff' });
// var(--acme-ui-color-primary)
See Class naming for how this pairs with createStyles({ scopeId }) for styles.
To share a cascade layer stack with styles, use createTypeStyles or pass layers and tokenLayer to createTokens (see Cascade layers).
Creating tokens
Use tokens.create(prefix, object) to define a set of tokens:
import { tokens } from 'typestyles';
const space = tokens.create('space', {
xs: '4px',
sm: '8px',
md: '16px',
lg: '24px',
});
const color = tokens.create('color', {
primary: '#0066ff',
text: '#111827',
border: '#e5e7eb',
});
Each value becomes a CSS custom property: --space-xs, --color-primary. The create function returns an object of the same shape whose values are var(--prefix-key) so you can use them in styles:
padding: space.md, // var(--space-md)
backgroundColor: color.primary, // var(--color-primary)
When you use createTypeStyles({ scopeId: 'app' }), the same tokens instance emits scoped names (for example --app-space-md). Add new namespaces in any module that imports tokens from your shared ./typestyles module:
import { tokens } from './typestyles';
export const space = tokens.create('space', {
sm: '8px',
md: '16px',
});
// With scopeId 'app': padding: space.md → var(--app-space-md)
Referencing tokens defined elsewhere
When tokens are created in another module or package, use tokens.use(namespace) to get the same var(--namespace-key) references without emitting another :root rule. The namespace must already be registered (via tokens.create) before those variables exist in CSS.
Type inference (cross-package)
tokens.create() returns a branded ref. Pass that ref to tokens.use() so consumers get the same typed shape without duplicating a manual generic:
// design-system/tokens.ts
export const space = tokens.create('space', { sm: '8px', md: '16px' });
// app/styles.ts
import { space as spaceTokens } from '@acme/design-system';
const space = tokens.use(spaceTokens);
space.md; // string — typed as var(--space-md)
For string-only lookups inside one package, declare a registry on createTokens<Registry>():
type DesignTokens = {
space: { sm: '8px'; md: '16px' };
color: { primary: '#0066ff' };
};
const tokens = createTokens<DesignTokens>();
const space = tokens.use('space'); // typed from Registry
Export InferTokenValues<typeof created> when consumers must reference tokens by namespace string.
Theming
Use tokens.createTheme(name, config) to register a theme surface: a class theme-{name} whose custom properties override token values for that subtree.
base— Overrides always applied on the surface (typical light / default brand).modes— Extra layers with explicittokens.when.*conditions.colorMode— Preset layers fromtokens.colorMode.*(mutually exclusive withmodes).
const dark = tokens.createTheme('dark', {
base: {
color: {
primary: '#66b3ff',
text: '#e0e0e0',
surface: '#1a1a2e',
},
},
});
createTheme returns a ThemeSurface (className, name, string coercion). Pass dark.className to DOM or React className props, or use String(dark) / `${dark}` in templates.
document.body.classList.add(dark.className);
Shorthand — dark under prefers-color-scheme only:
const autoDark = tokens.createDarkMode('app', {
color: { text: '#e5e7eb', surface: '#0f172a' },
});
Preset — system + data-color-mode toggle:
const light = { color: { text: '#111', surface: '#fff' } };
const dark = { color: { text: '#eee', surface: '#111' } };
const shell = tokens.createTheme('shell', {
base: light,
colorMode: tokens.colorMode.systemWithLightDarkOverride({
attribute: 'data-color-mode',
values: { light: 'light', dark: 'dark', system: 'system' },
scope: 'ancestor',
light,
dark,
}),
});
Other presets: tokens.colorMode.mediaOnly, attributeOnly, mediaOrAttribute. Condition primitives: tokens.when.media, prefersDark, attr, className, selector, and, or, not.
See Theming patterns for end-to-end examples.
Interop with DTCG and Style Dictionary
If your tokens originate in Figma, Tokens Studio, or another design tool that emits the W3C Design Tokens Community Group (DTCG) JSON format, use Style Dictionary as a build step that emits a plain TypeScript primitives module — then feed that module into tokens.create(…) here. See Style Dictionary & W3C tokens for the full pipeline in both directions.