Skip to main content
Typography in Substrate is continuous. There is no set of named size steps to pick from — no xs through 3xl. You declare a base size and a modular ratio, and every text size in the system is that base raised to a power of the ratio, evaluated in CSS at use time so it tracks the user’s type-scale preference without a rebuild.

The typography block

An example, from the fictional Acme brand’s config.global.yaml:

heading-family and body-family

Required font stacks, as full CSS font-family strings. They reach the browser as --font-heading and --font-body on the brand selector, and components resolve through --surface-font-family. A family can share one stack and let a sub-brand diverge on a single field — the fictional Aurora Airways family might pair "'Aurora Sans', Verdana, system-ui, sans-serif" for both, with its Rewards sub-brand overriding only the heading stack to a condensed cut.

mono-family

Optional. When omitted, the generated CSS falls back to a system monospace stack (ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace).

base-font-size

A number in rem, not a pixel string. Every bundled demo brand uses 1, which emits --font-size-base: 1rem. This is the size of the baseline text role, and every other size is derived from it.

scale-ratio

The modular ratio the scale raises to a power. 1.25 (major third) suits an editorial scale, 1.2 (minor third) a denser transactional one, and a data-heavy sub-brand might tighten further to 1.15. This is the authored ratio — the effective one is computed at runtime.

fluid

Optional responsive behavior. rate is the viewport or container coefficient used in the clamp() preferred value; floor and ceiling bound how far a size may shrink or grow as ratios of the computed size; quantum sets the rounding step in rem. Per-role fluid envelopes additionally carry absolute min and max in rem and can choose reference: viewport or container.

density

Optional signed coefficients linking type to the density slider. font-size-k controls how much --density pushes font size, and font-weight-k how much it pushes weight. The bundled demo brands all set both to 0, which decouples type from density — but a brand that wants text to tighten alongside spacing can dial them up.

The continuous scale

The authored scale-ratio is not used directly. The runtime first blends it toward 1 by the user’s type-scale preference, producing an effective ratio, then raises that to the role’s exponent. From generated/global/css/tokens.gen.css:
Every size in the system then comes from one expression, evaluated per element:
The consequence is that a brand’s typographic personality is two numbers. Raising scale-ratio from 1.2 to 1.25 widens the gap between every pair of adjacent roles at once, and a user who prefers larger type moves typeScaleFactor up — bounded by flexibility.type-scale, which every bundled demo brand sets to { min: 0.9, max: 1.4 } — and the whole hierarchy expands proportionally without a regenerate.

Semantic text roles

What replaces named size steps is a small set of semantic roles, each with a fractional exponent into the scale. From generated/global/typescript/text-roles.gen.ts: Fractional exponents are the point. caption at -0.75 sits three-quarters of a step below body — a position no integer ladder can express. Each role also carries a fluid envelope with absolute rem bounds; body, for instance, is bounded to 0.875–1.5rem with a floor of 0.85 and a ceiling of 1.1. Roles compose with the density coefficients at the component level. A badge, for example, sets its own scale offset and lets the brand’s coefficients modulate it:
Fluid sizing needs no viewport configuration block — there is no such block in the schema. The brand-level fluid settings plus each role’s own envelope are the whole mechanism.
When a heading feels wrong, reach for scale-ratio before reaching for a role. The ratio moves the entire hierarchy coherently; a one-off role adjustment moves one thing and creates a new exception to maintain.

Spacing & Density

The same continuous treatment applied to space — one unit, scaled at each use site.

Brand Config Overview

The full schema and the kebab-case normalization rule.