Type Scale
A brand charter's type section is a ladder: display, then the heading levels, then body, then the small print. Each rung is a bound triple — a size, the leading that goes with it, and the weight it is set in. design.typeScale is where that ladder lives.
design:
typeScale:
h1:
size: '3rem'
lineHeight: 1.1
weight: 700
letterSpacing: '-0.02em'
body:
size: '1rem'
lineHeight: 1.6
caption:
size: '0.8125rem'
lineHeight: 1.4Every step is optional. An app that declares only h1 and body has a real, if short, scale — the key is meant to be adopted a rung at a time.
The twelve steps
The set is closed, and the order below is the order the ladder is published in — largest first — whatever order you wrote the keys in.
| Step | What it is |
|---|---|
display |
The one-off page-opening size, above h1. |
h1 |
Page title. One per page. |
h2 |
Section heading. |
h3 |
Sub-section heading. |
h4 |
Fourth-level heading. |
h5 |
Fifth-level heading. |
h6 |
Sixth-level heading. |
lead |
The standfirst paragraph that opens a page, set larger than body. |
body |
Running text. The step every other one is measured against. |
bodySmall |
Secondary running text: help text, dense tables. |
caption |
Labels, timestamps, footnotes. |
overline |
The small tracked-out eyebrow above a heading. |
A step name outside this list is refused by name at validation — h7 is reported as an unknown key rather than silently ignored. h1 through h6 are deliberately the same names the text component already emits as element:, so a step is something a renderer can bind to rather than a string it has to guess at.
What a step holds
| Member | Type | Notes |
|---|---|---|
size |
string |
Required. A number with px or rem — '3rem', '14px'. |
lineHeight |
number |
A unitless ratio: 1.5, not '1.5' and not '24px'. |
weight |
number |
100–900, the same ladder theme.fonts uses. |
letterSpacing |
string |
A number with px, rem or em — '-0.02em'. |
font |
string |
The name of a face declared in design.theme.fonts — 'title', not 'Inter'. |
size is the only required member, because a step declaring nothing but a size is a real and common state — the leading and weight inherit. A step declaring leading and no size names no size at all and cannot render.
font names a face rather than a family so the binding survives a retune: a step reading font: title follows the title face wherever you change it, whereas an inlined 'Inter' is a copy that goes stale silently. It is cross-checked against your declared faces, so an unresolvable name is refused rather than emitted as a dangling variable.
design:
theme:
fonts:
title:
family: Inter
fallback: 'system-ui, sans-serif'
typeScale:
display:
size: '4.5rem'
lineHeight: 1.05
weight: 800
font: titleWhat it emits
Every declared step becomes a Tailwind type token: one custom property for the size and one modifier for each optional member.
:root {
--text-h1: 3rem;
--text-h1--line-height: 1.1;
--text-h1--font-weight: 700;
--text-h1--letter-spacing: -0.02em;
--text-h1--font-family: var(--font-title);
}The variables reach :root unconditionally, so anything can read var(--text-h1). The matching text-h1 utility is generated the way every Tailwind utility is — when the class name appears in a className the build-time scan can see:
pages:
- path: /
components:
- type: text
element: h1
props:
className: text-h1
content: CharterApplying the utility sets the font size and folds in the leading, weight, tracking and face in one class. That is the whole point of the key: a step you can use, not a variable nobody can reach.
Why the units are what they are
Each constraint tracks the W3C Design Tokens type the step serialises to, because a value the export cannot carry faithfully is a value the charter cannot publish.
sizetakespxorremand nothing else. Those are the two units a DTCGdimensionpermits. A fluidclamp(1rem, 2vw, 3rem)is refused rather than quietly accepted: fluid type is a layout technique for the one element that needs it, whereas a type scale is a ladder of fixed, quotable steps — "our h1 is 3rem" is the kind of sentence a charter exists to make true. Reach for a utility class on that element instead.lineHeightis a number, not a string. DTCG types it as a number, and the better practice agrees independently: a ratio survives a size change, whereas a fixed24pxleading silently becomes wrong the moment the step is retuned.letterSpacingadditionally takesem, which DTCG does not.-0.02emis the idiomatic tracking value in essentially every type scale ever written, and refusing it to satisfy a serialisation format would be the format dictating the design. It is honoured in the browser verbatim, and named in the export'sunmappablelist at its exact config path — so you can see that Sovrium rendered it and could not carry it in the token document.
What it supersedes
design.typeScale replaces three theme.fonts.* fields that validate and then reach nothing:
| Superseded | What it actually did |
|---|---|
theme.fonts.*.lineHeight |
Nothing at all. No custom property was ever emitted for it. |
theme.fonts.*.size |
Reached only the legacy hero section renderer, as an inline size. Never a CSS variable. |
theme.fonts.*.weights |
Only weights[0] was read, by that same renderer. Never an @font-face, so the extra entries loaded no font file. |
Superseded, not deprecated — the distinction is worth keeping. "Deprecated" means this worked and is going away; these three never worked. They keep decoding until the next major, alongside the top-level theme alias, because refusing them now would stop a booting app in exchange for zero rendering change. sovrium validate prints a Superseded: notice naming each declared path and exits 0.
They are not translated for you. The shapes genuinely differ — typeScale is per step where theme.fonts is per face, its lineHeight is a ratio where the old one was a free string, and it takes one weight where the old one took an array — so any automatic mapping would have to guess which face is which rung of the ladder. Sovrium says so instead of guessing.
In the export
sovrium design-system and the two admin export endpoints publish the ladder as a Type scale section, in the canonical order above. In the DTCG document each step is a typography composite token, with letterSpacing values in em listed under unmappable for the reason given above.
Related Pages
- Design System — the
designkey this belongs to, and the export. - Typography —
theme.fonts, the faces a step is set in. - Theme Overview & Colors — the other token categories.
- Content Components — the
textcomponent a step is applied to. - Design System Console — the ladder drawn at its rendered sizes.
Last updated August 28, 2026
This documentation was written with AI, so errors or outdated content are possible. Sovrium is in beta. Contributions and corrections are welcome.