UI.MD

Typography

Geist Sans for UI text, Geist Mono for code. A custom type scale from 2xs to jumbo with strict tracking rules for precise typographic control.

Type scale

11 sizes from 2xs (11px) to jumbo (45px). Finer granularity than Tailwind defaults below base.

TokenSpecimenSize
2xs

The quick brown fox

leading14.85px (snug)

11px
1xs

The quick brown fox

leading16.2px (snug)

12px
xs

The quick brown fox

leading19.5px (normal)

13px
sm

The quick brown fox

leading21px (normal)

14px
base

The quick brown fox

leading24px (normal)

16px
lg

The quick brown fox

leading27px (normal)

18px
xl

The quick brown fox

leading27px (snug)

20px
2xl

The quick brown fox

leading32.4px (snug)

24px
3xl

The quick brown fox

leading37.8px (snug)

28px
display

The quick brown fox

leading43.92px (1.22)

36px
jumbo

The quick brown fox

leading48.15px (1.07)

45px

Semantic roles

The scale is sized, not role-named. These are page-title and display roles for marketing and hero moments, not the site’s actual h1h3 defaults; see “Heading defaults” below for what headings render at in docs content. Pair reading roles with max-w-measure and headings with max-w-measure-heading.

RoleTierSize
Fine Printtext-1xs12px
Captiontext-sm14px
Bodytext-base16px
Leadtext-lg18px
Subheadtext-xl20px
Page title (H3-scale)text-2xl24px
Page title (H2-scale)text-3xl / text-display28 / 36px
Display (H1-scale)text-display / text-jumbo36 / 45px

Font families

Two families: one for interface, one for code.

Geist Sansfont-sans

Components

The primary interface font. Clean, neutral, and readable from micro labels to display headings.

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789

Geist Monofont-mono

npx shadcn add

Code blocks, terminal commands, data labels, and technical values.

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789

Font weights

Three weight levels, from light body text to heading emphasis.

WeightUsageValue
RegularLight or secondary text400
MediumBody copy, base text500
SemiboldHeadings, labels, emphasis600

Heading defaults

What ships. h2 and h3 are what DocSection and DocSubsection actually render, not the display roles above.

ElementSpecimenSize
h1Page Title28px
h2Section Heading18px
h3Subsection16px
h4Label / Overline12px

Line height

Four levels from tight display text to comfortable long-form reading.

ClassSpecimenValue
leading-tight

Typography is the craft of endowing human language with a durable visual form. Good typography is measured by how well it reinforces the meaning of the text, not by how much attention it draws to itself. The best typography is invisible. It serves the reader without being noticed.

1.25
leading-snug

Typography is the craft of endowing human language with a durable visual form. Good typography is measured by how well it reinforces the meaning of the text, not by how much attention it draws to itself. The best typography is invisible. It serves the reader without being noticed.

1.35
leading-normal

Typography is the craft of endowing human language with a durable visual form. Good typography is measured by how well it reinforces the meaning of the text, not by how much attention it draws to itself. The best typography is invisible. It serves the reader without being noticed.

1.5
leading-reading

Typography is the craft of endowing human language with a durable visual form. Good typography is measured by how well it reinforces the meaning of the text, not by how much attention it draws to itself. The best typography is invisible. It serves the reader without being noticed.

1.625

Letter spacing

Tighten display headings, loosen uppercase labels. Body text rides the font's default metrics.

ClassUsageValue
tracking-tightHeadings (xl and up)-0.025em
tracking-wideUppercase labels, overlines0.08em (8%)

Composition

How the type tokens combine in real UI patterns.

Page Header

A concise description that explains what this page is about and what the user can do here.

Card Header

Supporting text that provides additional context below the title.

Section Title

Section body text at the default size with normal line height for comfortable reading.

Tertiary info like a timestamp or metadata

OVERLINE LABEL

Content beneath an overline label, often in a sidebar or settings panel.

Long-form prose

A full article composition: how headings, body, lists, links, and code read together.

Design System

Typography is the voice of the interface

Good type is invisible. It serves the reader without asking for attention. This is how the system composes at reading length.

Matt Downey·8 min read·April 2026

Every interface is a sequence of typographic decisions. Size, weight, tracking, and rhythm do most of the work before color or layout ever get a turn. A system that gets type right feels calm; a system that gets it wrong feels noisy no matter how many other details are polished.

The scale here spans eleven sizes, from text-2xs for dense metadata up to text-jumbo for marketing moments. Most of your UI will live between text-xs and text-lg.

Hierarchy, not decoration

Headings exist to help the eye skim, not to announce importance. Use them sparingly, and let weight and size carry the structure. When every heading shouts, none of them do.

A few rules worth internalizing:

  • Never skip levels: an h2 follows an h1, not an h3.
  • Keep measure tight: aim for 60 to 75 characters per line for body copy.
  • Trust the scale: if a size doesn’t exist in the system, extend the scale rather than reach for an arbitrary value.

A typical workflow

When composing a new page, start from the outside in:

  1. Pick the page-level heading size first: this anchors everything else.
  2. Set the body size and line height to match the reading context.
  3. Fill in supporting sizes last: overlines, captions, metadata.

For inline emphasis, prefer semantic weight over italics. Links should feel like links: we use underlined accent color so they read clearly in both paragraphs and lists.

Typography has one plain duty before it and that is to convey information in writing.
Emil Ruder

Code in prose

Inline tokens like font-semibold or leading-reading sit comfortably mid-sentence. Longer examples get their own block:

export function Button({ children }: { children: React.ReactNode }) {
  return (
    <button className="h-8 px-4 rounded-lg bg-accent text-accent-foreground">
      {children}
    </button>
  )
}

The body font is Geist Sans and code uses Geist Mono. Both are variable fonts, so weights blend cleanly across the whole scale.

font-sans is a chain: your override, then Geist Sans, then the system UI font. Install nothing and you get Geist, free via the geistnpm package. That is the kit’s default and no component ships or requires a licensed typeface. This site sets no override at all, which is the point: every specimen on this page is the default, so what you are reading is exactly what a fresh install renders. Nothing here flatters the kit with a face you would not get. The kit also sets Geist’s letterforms for you, on body: single-storey a, straight l, straight-leg R, alternate i and j, and tabular figures so a number that ticks does not reflow the text beside it. Because font-feature-settings replaces rather than merges, re-declaring it on an element switches off everything you leave out. Two catches if you do swap the face. A font package built from Google’s sources is stripped of its OpenType features, so a face chosen for its alternates will quietly arrive without them. And those set numbers name specific alternates in Geist and mean something else in another family, so re-declare the list against your own font.


This specimen is itself rendered with the system’s tokens: no custom typography CSS. If a line looks off here, it’ll look off everywhere.