Skip to content
Highlight

FoundationsUpdated Sep 22, 2026

Typography

Eight sizes in two bands. Text sits at 18 and below, headings at 20 and above, so a heading never has to be told apart from a paragraph set in semibold. Every step carries its own leading and tracking, so one class is one decision.

Pick a role, then a weight. Never pick a leading or tracking by hand.

  • A sentence is prose, anything else is UI. At a shared step they differ by figures and wrapping, not by size.
  • Weight is separate. Roles never set it; add font-medium or font-semibold.
  • There is no 14, 16 or 20. 14 is sm, 16 is md, 20 is lg. An arbitrary text-[…px] is a review flag.
  • text-xs, text-sm, text-md and text-lg are the UI steps. They are the only text-* sizes: sm is the 13px default, and there is no text-base or text-xl. Each carries the UI role's leading and tracking, and as utilities they override a primitive's own size. Reach for type-* when the role matters: prose, code, or a heading (type-h3 to type-display).
tsx
// A role sets size, leading, tracking and figures together<span className="type-ui-sm text-foreground-secondary">Updated 2 min ago</span><p className="type-prose-md">Meeting notes stay in sync across devices.</p><h2 className="type-h2">Tuesday standup</h2> // Weight composes on top; the role never sets it<button className="type-ui-md font-medium">Save</button><h1 className="type-h1 font-medium">Softer page title</h1> // Plain text-* still works and now carries leading + tracking<span className="text-sm">13 / 18</span>

Sizes are authored in px and emitted in rem against a 16px root. Tracking follows Inter's dynamic metrics.

SizeLeadingTrackingUtilityVariables
12px16px0.001emtext-xs--font-size-12 · --line-height-16 · --tracking-12
13px18px-0.003emtext-sm--font-size-13 · --line-height-18 · --tracking-13
14px20px-0.006emtext-md--font-size-14 · --line-height-20 · --tracking-14
18px26px-0.014emtext-lg--font-size-18 · --line-height-26 · --tracking-18
22px28px-0.018emtype-h3--font-size-22 · --line-height-28 · --tracking-22
28px34px-0.021emtype-h2--font-size-28 · --line-height-34 · --tracking-28
36px42px-0.022emtype-h1--font-size-36 · --line-height-42 · --tracking-36
48px54px-0.022emtype-display--font-size-48 · --line-height-54 · --tracking-48

Controls, labels, rows, anything that is not a sentence. Pixel leading so rows stack on a grid, tabular figures so numbers hold their width.

Save changes · 12:45 PM · 1,204 items

type-ui-xs
size
12px
leading
16px
tracking
0.001em

Captions, timestamps, badges

Save changes · 12:45 PM · 1,204 items

type-ui-sm
size
13px
leading
18px
tracking
-0.003em

Default control and body size: labels, list rows, menu items

Save changes · 12:45 PM · 1,204 items

type-ui-md
size
14px
leading
20px
tracking
-0.006em

Roomier controls and body text

Save changes · 12:45 PM · 1,204 items

type-ui-lg
size
18px
leading
26px
tracking
-0.014em

Prominent controls, dialog titles

Running text. Same sizes as UI but a unitless 1.5 leading that recomputes for nested sizes, proportional figures, and pretty wrapping.

Meeting notes stay in sync across devices, so the summary you edit on the desktop is the one you share.

type-prose-xs
size
12px
leading
1.5
tracking
0.001em

Fine print

Meeting notes stay in sync across devices, so the summary you edit on the desktop is the one you share.

type-prose-sm
size
13px
leading
1.5
tracking
-0.003em

Dense reading: transcripts, side panels

Meeting notes stay in sync across devices, so the summary you edit on the desktop is the one you share.

type-prose-md
size
14px
leading
1.5
tracking
-0.006em

Body copy, chat messages, notes

Meeting notes stay in sync across devices, so the summary you edit on the desktop is the one you share.

type-prose-lg
size
18px
leading
1.5
tracking
-0.014em

Lead paragraphs

Monospace on the same four steps. No tracking, no ligatures, tabular figures.

const summary = await meeting.summarize({ speakers: 3 })

type-code-xs
size
12px
leading
16px
tracking
0em

Inline code inside sm and xs text

const summary = await meeting.summarize({ speakers: 3 })

type-code-sm
size
13px
leading
18px
tracking
0em

Code blocks, inline code in md text

const summary = await meeting.summarize({ speakers: 3 })

type-code-md
size
14px
leading
20px
tracking
0em

Editors

const summary = await meeting.summarize({ speakers: 3 })

type-code-lg
size
18px
leading
26px
tracking
0em

Presentation code

Four steps above the text band, each with leading of size + 6, all semibold. Display alone is set in the brand face, Greed Standard, and falls back to Inter where it is not loaded.

Tuesday standup with the design team

type-h3
size
22px
leading
28px
tracking
-0.018em
weight
semibold

Section headings

Tuesday standup with the design team

type-h2
size
28px
leading
34px
tracking
-0.021em
weight
semibold

Page section titles

Tuesday standup with the design team

type-h1
size
36px
leading
42px
tracking
-0.022em
weight
semibold

Page titles

Tuesday standup with the design team

type-display
size
48px
leading
54px
tracking
-0.022em
weight
semibold

Hero and empty-state statements, in the brand face

One TypeScript module is the source of truth. A Tailwind plugin emits the variables and classes; this page imports the same module.

css
/* packages/ui/src/styles/typography.ts emits three layers */ /* 0. primitives */:root { --font-size-14: 0.875rem; --line-height-20: 1.25rem; --tracking-14: -0.006em; } /* 1. roles */:root { --ui-md-size: var(--font-size-14); --ui-md-leading: var(--line-height-20); } /* 2. classes, in the components layer so any utility overrides them */.type-ui-md {  font-size: var(--ui-md-size);  line-height: var(--ui-md-leading);  letter-spacing: var(--ui-md-tracking);  font-variant-numeric: tabular-nums;}