Design Tokens — typography
Typography sets the product’s tone more than many “visible” decorative choices. In a design system it must be a scale and a contract: families, sizes, weights, line-height, letter-spacing, and semantic roles (h1, body, caption).
Core typography axes
- Font family — brand character and readability.
- Font size — hierarchy and interface density.
- Font weight — emphasis without overusing bold.
- Line-height — line rhythm and paragraph readability.
- Letter-spacing — headings, uppercase, compact labels.
- Type scale — a regular size system, not a random set of px values.
Choosing families and pairing
System stack
Maximum performance, zero download, familiar OS look. Con — weaker brand uniqueness.
Web fonts (for example, Inter + Fira Code)
A balance of control and speed. You need font-display, a sensible set of weights, and fallbacks.
Custom / self-hosted
Maximum brand and subsetting control, but licenses, infrastructure, and bundle size are your responsibility.
A practical pairing for product UI:
- Sans for the interface (Inter / system-ui);
- Mono for code and technical values;
- optionally Display/Serif only for marketing headlines, not dense app screens.
Do not mix four decorative families “for beauty” — usually 1–2 are enough.
Type scale
Recommended body base — 16px (1rem). Then a modular scale:
export const fontSize = {
xs: '0.75rem', // 12px
sm: '0.875rem', // 14px
base: '1rem', // 16px
lg: '1.125rem', // 18px
xl: '1.25rem', // 20px
'2xl': '1.5rem', // 24px
'3xl': '1.875rem',// 30px
'4xl': '2.25rem', // 36px
'5xl': '3rem' // 48px
};
export const fontWeight = {
normal: 400,
medium: 500,
semibold: 600,
bold: 700
};
export const lineHeight = {
tight: 1.25,
normal: 1.5,
relaxed: 1.75
};
Semantic typography
Sizes alone are not yet a system. You need roles:
export const text = {
h1: { size: '4xl', weight: 'bold', leading: 'tight', tracking: 'tight' },
h2: { size: '3xl', weight: 'bold', leading: 'tight' },
h3: { size: '2xl', weight: 'semibold', leading: 'tight' },
body: { size: 'base', weight: 'normal', leading: 'normal' },
caption: { size: 'xs', weight: 'normal', leading: 'normal' }
};
Then designer and engineer speak the same language: “this is body,” not “this is roughly 15–16px.”
Line-height and letter-spacing
- Headings: tighter leading (about 1.1–1.3), often slightly negative tracking.
- Body: 1.4–1.6.
- Long-form: closer to 1.6–1.8.
- Uppercase labels: positive letter-spacing, otherwise they “stick together.”
Responsive typography
Two workable approaches:
- Fluid via
clamp()for heroes and headings. - Breakpoint-based tokens for UI where predictability matters.
.heading-hero {
font-size: clamp(2rem, 4vw + 1rem, 3rem);
line-height: 1.15;
}
Do not make the whole interface “rubbery” without need: forms and tables often work better on a discrete scale.
Accessibility
- Body no smaller than 16px without a strong reason.
- Text should scale to 200% without breaking layout.
- Use
rem/emfor interface sizes. - Text contrast follows the same rules as color tokens.
- Do not convey meaning only through light weight on gray.
Typography tokens matter for a11y as much as color tokens: tiny low-contrast text “looks nice” in a mock and works poorly for real users.
Lesson takeaway
A good typography system = limited pairing + regular scale + semantic roles + checked line-height/tracking + responsive rules. That is the readability foundation of the whole DS.