One type system, seven token families, applied with a single utility class.
Create UI ships a single, unified type system. Every text style is a token, and each token is applied with one text-{token} utility class that carries its font size, line height, letter spacing, and weight together. You name the role the text plays (text-heading-h1, text-paragraph-md, text-numeric-xl) instead of tuning four separate properties by hand.
One system, many roles: every screen is typed once against these tokens, and a token already knows its metrics at every breakpoint. Retuning the scale or shifting a heading down a size never touches markup.
Why one class
The same heading, written two ways:
The payoff:
- One decision, not four. Size, line height, letter spacing, and weight travel together, so they can never drift out of sync on a stray element.
- Responsive for free. The three breakpoints live inside the token, not in your markup. There is nothing to remember and nothing to copy-paste.
- Consistent by construction. Two
text-heading-h2elements are identical everywhere, because there is one definition, not dozens of arbitrary values. - One place to change. Retuning the scale happens in a single data file, not a search-and-replace across every
text-[…]in the app.
You never pair a token with leading-*, tracking-*, or font-*. The class already resolves line height, letter spacing, and weight from its category. Choosing the token is the whole decision.
Usage
Apply a token class to any element. The class sets everything the style needs.
Tokens compose. A real section is just a few of them stacked, each one naming its role and pairing with a color token:
That snippet rendered, with each token doing its job:
Team plan
Everything your whole team needs to ship a consistent product, billed once per seat.
$4,299Team plan
Everything your whole team needs to ship a consistent product, billed once per seat.
$4,299How it works
A token flows through three layers before it reaches your markup.
1. Token data is the source of truth. Each token is defined as plain data: a category plus its responsive metrics, written [mobile, tablet, desktop].
The category (heading) supplies the font family and default weight; the size step (h1) supplies the metrics.
2. CSS custom properties. The build expands each token into four --text-* variables on :root, then overrides the responsive ones in two max-width media queries:
3. Tailwind utilities. Those variables are registered in @theme inline, so Tailwind v4 generates the text-* utility from them:
The result is a single class that already knows its four metrics at every breakpoint. When a project runs createui init, the CLI emits the same variables into the consumer's stylesheet, so the type scale travels with the components.
Anatomy of a token
Token names follow a category-size shape:
heading-h1 → category: heading size: h1
numeric-xl → category: numeric size: xl
ui-overline-sm → category: ui / overline size: sm
The category decides the font family and default weight. The size decides the metrics. Pick a token and you have picked the right typeface, the right weight, and the right scale step in one move.
Categories
Seven families cover every role, from marketing display type down to dense numeric and code data. Reach for the family that matches the job, not the one that happens to look the right size.
Each family has its own personality. body is tight and functional for UI copy; paragraph opens up its line height for comfortable reading; numeric switches to a monospace face for figures that line up in columns:
Body: dense, functional copy for product UI.
Paragraph keeps the same family but opens up its line height, so a long block of running text stays comfortable to read across several lines.
1,284 · $4,299 · 99.9%createUI()Body: dense, functional copy for product UI.
Paragraph keeps the same family but opens up its line height, so a long block of running text stays comfortable to read across several lines.
1,284 · $4,299 · 99.9%createUI()Live specimen
Every token in the system, rendered at its real responsive metrics with its desktop size, line height, tracking, and weight printed alongside.
Font families
Three font variables back the categories, each defined with next/font in lib/fonts.ts and exposed as a CSS variable on the document root:
--font-displayand--font-bodyare both Geist (sans-serif). Display, heading, body, paragraph, and ui all read from these.--font-numericis JetBrains Mono (monospace), giving prices, stats, and code consistent tabular width. Bothnumericandcodeuse it.
You never set the family directly. Choosing a token in a category applies its font automatically.
Responsive scale
Token values are defined per breakpoint as [mobile, tablet, desktop]. The generated CSS sets the desktop value on :root and overrides it with two max-width media queries:
Large type scales down on smaller screens, while interface, numeric, and code type stay fixed so controls and data never shift size:
- Display and heading scale their font size and letter spacing. Line height is a percentage, so it tracks the font size automatically at every breakpoint.
- Body and paragraph keep their font size fixed and open up line height slightly on smaller screens for readability.
ui,numeric, andcodeare fixed at every breakpoint.
For example, heading-h1 steps down as the viewport narrows:
Guidelines
Do name the role with a single token. Avoid arbitrary text-[…] values and hand-tuned leading-* / tracking-* / font-* in product and site code.
- Use
headinganddisplayfor titles,bodyfor UI copy,paragraphfor long-form reading,uifor controls,numericfor figures,codefor code. - Let the token own its metrics. If you find yourself adding
leading-*ortracking-*next to atext-{token}, the wrong size step is almost always the real fix. - Reserve arbitrary
text-[…]values for the rare one-off that genuinely has no role in the scale. - Pair a type token with a color token (
text-strongest,text-body,text-placeholder) rather than baking color into the type choice.
Token reference
Every token in the system, grouped by category. Responsive values are written desktop / tablet / mobile; a single value is fixed across all breakpoints. Sizes and pixel line heights are in pixels. Display, heading, and code line heights are percentages, so they stay proportional as the font size changes.
Display
Heading
Body
Font size is fixed; line height opens up slightly on mobile for readability.
Paragraph
UI
Fixed at every breakpoint so controls never resize.
UI / Overline
Uppercase labels with widened tracking, for eyebrows and section kickers.
UI / Caption
Numeric
JetBrains Mono, fixed at every breakpoint.
Code
JetBrains Mono, fixed at every breakpoint.
Editing the scale
Tokens are data, not hand-written CSS. Change a value in
lib/createui-typography.ts, run pnpm tokens:build and pnpm registry:build, and every text-* utility regenerates from the new
definition.