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.
There are 37 of them across seven families. Every token knows its metrics at every breakpoint, so a class like text-heading-h1 resolves to a different size on a phone, a tablet, and a desktop, while the families that are deliberately fixed resolve to the same value everywhere:
One class, three values. The outlined panel is your screen right now, so resize the window and watch it move.
2 media queries in the system, 0 in your markupWhy 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.
- 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-* or tracking-*. The class resolves size, line height, and letter spacing from the token itself, and weight from its category, so those four can never drift apart.
Three token groups ask for one companion class alongside the size token: numeric and code take font-numeric for the mono face, and ui-overline-* takes uppercase. The token reference prints the companion on every row that needs one.
Anatomy of a token
Token names follow a category-size shape:
heading-h1is categoryheading, sizeh1numeric-xlis categorynumeric, sizexlui-overline-smis categoryui / overline, sizesm
The category decides the default weight and which companion class the token expects. The size decides the metrics. Pick a token and you have picked the right weight and the right scale step in one move.
Usage
Apply a token class to any element. The class sets the four metrics; the companion class, where a family needs one, sets the face or the casing.
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 in both themes:
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,299Three font variables back the families. In a Next.js project createui init declares them with next/font in your root layout; elsewhere it imports the equivalent Fontsource packages. --font-display and --font-body are both Geist, and the page default, so most tokens need no face class at all. --font-numeric is Geist Mono, which gives prices, stats, and code a consistent tabular width, and is what font-numeric selects.
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 styles 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.
- Paragraph and the larger body steps keep their font size fixed and open up line height slightly on smaller screens for readability. The two smallest body steps are fixed outright.
ui,numeric, andcodeare fixed at every breakpoint, so controls and data never shift size.
Token reference
Every token in the system, rendered at its real metrics. The sample sets on the left; the spec rail on the right prints size, then line height, then letter spacing, each value behind a phone, tablet, or desktop mark so the whole curve reads without decoding an arrow. A single number in place of the three marks means that metric is fixed at every breakpoint, which is why most rows carry a mix. The family's weight and face sit in the card header, and clicking a token name copies its full utility class.
- Use
headinganddisplayfor titles,bodyfor UI copy,paragraphfor long-form reading,uifor controls,numericfor figures,codefor code. - Pair a type token with a color token (
text-strongest,text-body,text-placeholder) rather than baking color into the type choice.
How it works
You do not need this to use the tokens, but it helps to know the numbers are generated, not hand-written.
A token flows through three layers before it reaches your markup.
1. Token data. 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. buildTypographyCssVars() in registry/config.ts turns each token into its four values, and the CSS writer expands them into four --text-* variables on :root, overriding the responsive ones in two max-width media queries. Those two blocks are the only @media rules in the whole stylesheet:
3. Tailwind utilities. Those variables are registered in @theme inline, so Tailwind v4 generates the text-* utility from them, and the class 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.
Editing the scale
The scale is data, not hand-written CSS. Override any --text-* variable in
your own globals.css and the @theme inline block regenerates the matching
utility, or re-run npx @create-ui/cli init to pull the current scale.