How to pipe typography tokens through style dictionary
- Step 1Generate the scale and copy the values — Set Family, Base size, Ratio, and Steps. Copy the `:root` block. The numbers you care about are the `--font-size-*` rem values and the fixed weight/line-height tokens — those become your Style Dictionary token values.
- Step 2Decide your token unit — The output is rem. For web, rem maps cleanly. For iOS you'll want pt (multiply rem by your base px), for Android sp (same idea). Decide whether your tokens JSON stores rem (and Style Dictionary transforms it) or stores px (and you convert once).
- Step 3Transcribe sizes into tokens JSON — Write each `--font-size-lg: 1.250rem` as a token: `{ "font": { "size": { "lg": { "$value": "1.25rem", "$type": "dimension" } } } }`. The generator does not emit this JSON — you author it from the copied values, or run the parse script below.
- Step 4Add the fixed groups — Mirror the weights (300–800), line-heights (1.2–2), and letter-spacings (±0.05em) as tokens too. They're constant across every generation, so you can keep these JSON fragments in a reusable partial.
- Step 5Configure Style Dictionary platforms — In your config, define `css` (transformGroup `css`), `ios-swift`, and `android` platforms. Each gets a transform pipeline that converts your dimension tokens to the platform's unit and naming convention.
- Step 6Build and diff against the generated CSS — Run `npx style-dictionary build`. Diff `dist/css/typography.css` against the `typography-tokens.css` you downloaded from this tool — the size values should match, confirming your translation was faithful.
What the tool emits vs what Style Dictionary needs
The gap you bridge by hand. The generator is a CSS source; Style Dictionary is a JSON-driven multi-platform compiler.
| Aspect | This generator | Style Dictionary input |
|---|---|---|
| Format | CSS :root block (text/css) | Tokens JSON (W3C $value/$type or legacy) |
| Sizes | rem, three decimals | dimension tokens (rem/px), transformed per platform |
| Naming | Tailwind labels xs→8xl | Your choice; transforms rename per platform |
| Export here | Copy or download CSS | You author JSON from the values |
| Fluid | No (static rem only) | n/a — handled in your token math if needed |
rem → platform unit conversion (base 16px)
How the generated rem values translate when you transcribe into tokens for each platform. Style Dictionary transforms automate this if you store rem; the px reference helps you verify.
| Generated rem | Web (rem) | iOS (pt, ×16) | Android (sp, ×16) |
|---|---|---|---|
0.800rem (sm) | 0.8rem | 12.8pt | 12.8sp |
1.000rem (base) | 1rem | 16pt | 16sp |
1.250rem (lg) | 1.25rem | 20pt | 20sp |
1.563rem (xl) | 1.563rem | 25pt | 25sp |
2.441rem (3xl) | 2.441rem | 39.06pt | 39.06sp |
Fixed groups to mirror as tokens
These values are constant across every generation, so keep them as a reusable JSON partial in your Style Dictionary source.
| Token | CSS value | Suggested $type |
|---|---|---|
| weight.regular / .bold | 400 / 700 | fontWeight |
| lineHeight.tight / .normal | 1.2 / 1.5 | number |
| letterSpacing.tight / .wide | -0.025em / 0.025em | dimension |
| family.base | "Inter", system-ui, … | fontFamily |
Cookbook
The translation from generated CSS to a Style Dictionary source, including a parse script so you don't transcribe by hand.
Generated CSS (the source you copy)
ExampleDefault settings. These are the lines a parse script reads. Fixed groups trimmed.
:root {
--font-family-base: "Inter", system-ui, ...;
--font-weight-regular: 400;
--font-weight-bold: 700;
--line-height-normal: 1.5;
--font-size-xs: 0.640rem;
--font-size-sm: 0.800rem;
--font-size-base: 1.000rem;
--font-size-lg: 1.250rem;
--font-size-xl: 1.563rem;
--font-size-2xl: 1.953rem;
--font-size-3xl: 2.441rem;
}Target tokens JSON (you author this)
ExampleW3C Design Tokens shape. The generator does not produce this — it's the destination of your translation.
{
"font": {
"size": {
"xs": { "$value": "0.64rem", "$type": "dimension" },
"sm": { "$value": "0.8rem", "$type": "dimension" },
"base": { "$value": "1rem", "$type": "dimension" },
"lg": { "$value": "1.25rem", "$type": "dimension" },
"xl": { "$value": "1.563rem", "$type": "dimension" }
},
"weight": {
"regular": { "$value": 400, "$type": "fontWeight" },
"bold": { "$value": 700, "$type": "fontWeight" }
}
}
}Parse script: CSS → tokens JSON
ExampleA throwaway Node snippet that turns the downloaded typography-tokens.css into a tokens object, so you don't transcribe by hand. Reads only the --font-size-* lines.
const fs = require('fs');
const css = fs.readFileSync('typography-tokens.css', 'utf8');
const size = {};
for (const m of css.matchAll(/--font-size-([\w-]+):\s*([\d.]+)rem/g)) {
size[m[1]] = { $value: parseFloat(m[2]) + 'rem', $type: 'dimension' };
}
fs.writeFileSync('tokens.json',
JSON.stringify({ font: { size } }, null, 2));
// → tokens.json ready for Style DictionaryStyle Dictionary config
ExampleStandard multi-platform config consuming the tokens.json you built. Each platform gets its own transformGroup.
// config.json
{
"source": ["tokens.json"],
"platforms": {
"css": { "transformGroup": "css", "files": [{ "destination": "dist/typography.css", "format": "css/variables" }] },
"ios": { "transformGroup": "ios-swift", "files": [{ "destination": "dist/Typography.swift", "format": "ios-swift/class.swift" }] },
"android": { "transformGroup": "android", "files": [{ "destination": "dist/typography.xml", "format": "android/resources" }] }
}
}Verify: generated CSS vs Style Dictionary CSS
ExampleRound-trip check. The size values in Style Dictionary's CSS output should equal the tool's output.
tool output: style-dictionary dist/typography.css: --font-size-lg: 1.250rem; --font-size-lg: 1.25rem; --font-size-xl: 1.563rem; --font-size-xl: 1.563rem; # values match → translation faithful # (1.250 vs 1.25 is the same number, trailing zero trimmed)
Edge cases and what actually happens
Every row below was probed against the live API. Some documented requirements (alphabetical axis order, numerical tuple order) are not actually enforced in practice — useful to know if you've been blaming the wrong thing for a 400.
Expecting a JSON/tokens export from the tool
Not supportedOutput type is css only. There is no JSON, W3C Design Tokens, or Style Dictionary export button. You translate the copied CSS values into JSON yourself (the parse script above automates the size tokens). This is the single most important fact for this workflow.
Trailing zero in rem (1.250 vs 1.25)
CosmeticThe tool prints three decimal places, so you'll see 1.250rem. parseFloat normalises this to 1.25 and Style Dictionary's CSS output also trims it. The numeric value is identical — don't treat the trailing zero as a mismatch.
rem-to-pt drift on iOS
Verify baserem→pt conversion assumes a 16px base. If you generated with a different Base size (say 18px), 1rem is 18px, so multiply rem by 18, not 16, when producing pt tokens. Store the base alongside your tokens so the transform uses the right factor.
Family name needs per-platform mapping
Handle in transformsThe CSS family token is a single web stack. iOS wants Inter-Regular, Android wants inter_regular. The tool can't do this — define a Style Dictionary transform that maps the web family name to platform-specific names. Generate once; map in the pipeline.
letter-spacing in em doesn't translate to native
Convert manually-0.025em is relative to font-size — native platforms often want absolute tracking. Decide a conversion (e.g. em × size_pt) when you author the token, since the tool emits em-relative values it has no way to resolve to absolute units.
Re-running with new inputs changes only the numbers
Stable shapeChanging Ratio or Base size changes the rem values but not the token names (xs→8xl). Your parse script and Style Dictionary config keep working — only the values update, which is exactly what you want for a re-tuned scale.
Steps beyond what your platforms use
Trim in JSONIf you generate 12 steps but iOS only ships 6 type styles, just omit the unused size tokens when you author the JSON. The generator gives you the full ladder; you decide which steps become platform tokens.
Wanting fluid (clamp) tokens cross-platform
Different sourceThis tool emits static rem; clamp() doesn't translate to native units anyway. For web-only fluid tokens use typography-scale-builder; for native, ship static size tokens and let each platform's dynamic-type system handle scaling.
Frequently asked questions
Does this tool output Style Dictionary JSON?
No. It outputs a CSS :root block only (text/css, downloaded as typography-tokens.css). To feed Style Dictionary you translate the values into a tokens JSON yourself — the parse script in the cookbook automates the size tokens from the downloaded CSS.
Why use this tool at all if I still write JSON?
It does the modular-scale math for you and gives a deterministic, previewable scale. Computing base × ratio^n for 9 steps by hand is error-prone; copy the verified rem values into your tokens instead.
Should my tokens store rem or px?
Either. Store rem and let Style Dictionary transforms convert to pt/sp per platform, or convert to px once (rem × base) and store absolute values. Storing rem is more portable; just record the base so conversions use the right factor.
Is the 1.250rem trailing zero a problem?
No — it's the same value as 1.25rem. parseFloat and Style Dictionary both normalise it. Only flag a mismatch if the actual number differs.
How do I handle font-family across platforms?
Define a Style Dictionary transform that maps the web family (e.g. Inter) to iOS (Inter-Regular) and Android (inter_regular.ttf). The generator emits one web stack; the per-platform naming is a transform concern.
Can I theme cross-platform from this source?
Yes, but theming lives in your Style Dictionary setup, not the generator. Author base tokens (translated from one generation) plus theme-override token sets; each platform's output includes both. The tool just supplies the base numbers.
Do the weight and line-height values translate directly?
Weights (400, 700, …) are numeric and translate as-is. Line-heights (1.5, etc.) are unitless multipliers and translate cleanly. Letter-spacings are in em and need a conversion to absolute units for native platforms.
Why is W3C Design Tokens format recommended for the JSON?
Style Dictionary supports it natively and other tools (Figma Token Studio, Backlight) read it, so your hand-authored tokens stay portable. Use the $value/$type shape shown in the cookbook.
Will regenerating break my pipeline?
No. The token names are stable (xs→8xl); only the numeric values change when you adjust ratio/base. Your parse script and config keep working — re-run the parse to refresh the values.
Can I generate fluid clamp() tokens for this pipeline?
Not from this tool, and clamp() doesn't translate to native units. Use static size tokens cross-platform and rely on each OS's dynamic-type scaling; for web-only fluid CSS, see typography-scale-builder.
Is anything uploaded when I generate?
No. It's a browser-only generative tool — no font file, no account. You copy or download the CSS locally, then run your translation offline.
How do I confirm my translation is correct?
Build with Style Dictionary and diff its CSS output against the typography-tokens.css the tool produced. The size values should match number-for-number (modulo trailing-zero cosmetics).
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.