Fonts
Font families, sizes, weights, line height and letter spacing — plus how to build a type scale with @theme and load custom fonts properly.
Type is the highest-leverage part of a design system. Tailwind gives you a scale for each axis and lets you redefine all of them from @theme.
Font family#
| Utility | Stack |
|---|---|
font-sans | System UI sans stack |
font-serif | System serif stack |
font-mono | System monospace stack |
@theme {
--font-display: "Satoshi", ui-sans-serif, sans-serif;
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
}That generates font-display and overrides font-sans.
Loading a web font#
@import "tailwindcss";
@font-face {
font-family: "Satoshi";
src: url("/fonts/Satoshi-Variable.woff2") format("woff2-variations");
font-weight: 300 900;
font-display: swap;
}
@theme {
--font-display: "Satoshi", ui-sans-serif, sans-serif;
}font-display: swap renders fallback text immediately instead of leaving a blank gap. Always include a real fallback stack.
For Next.js, see React & Next.js — it needs @theme inline.
Font size#
| Utility | Size | Default line height |
|---|---|---|
text-xs | 0.75rem | 1rem |
text-sm | 0.875rem | 1.25rem |
text-base | 1rem | 1.5rem |
text-lg | 1.125rem | 1.75rem |
text-xl | 1.25rem | 1.75rem |
text-2xl | 1.5rem | 2rem |
text-3xl | 1.875rem | 2.25rem |
text-4xl | 2.25rem | 2.5rem |
text-5xl … text-9xl | 3rem … 8rem | 1 |
Each size ships with a sensible line height, so text-lg alone is usually complete.
Overriding line height inline#
<p class="text-lg/7">Font size lg, line height 1.75rem</p>
<p class="text-2xl/tight">Font size 2xl, tight leading</p>The slash modifier sets line-height in one class.
Custom sizes#
@theme {
--text-hero: 4rem;
--text-hero--line-height: 1.05;
--text-hero--letter-spacing: -0.03em;
--text-hero--font-weight: 700;
}class="text-hero" now applies all four properties.
Font weight#
| Utility | Value |
|---|---|
font-thin | 100 |
font-extralight | 200 |
font-light | 300 |
font-normal | 400 |
font-medium | 500 |
font-semibold | 600 |
font-bold | 700 |
font-extrabold | 800 |
font-black | 900 |
Line height#
| Utility | Value | Good for |
|---|---|---|
leading-none | 1 | Large display headings |
leading-tight | 1.25 | Headings |
leading-snug | 1.375 | Subheadings |
leading-normal | 1.5 | Default |
leading-relaxed | 1.625 | Long-form body copy |
leading-loose | 2 | Sparse lists |
leading-6 | Spacing scale | Precise vertical rhythm |
The rule of thumb: larger text needs tighter leading, smaller text needs looser.
Letter spacing#
| Utility | Value | Use |
|---|---|---|
tracking-tighter | -0.05em | Very large display type |
tracking-tight | -0.025em | Headings |
tracking-normal | 0 | Body |
tracking-wide | 0.025em | Small caps |
tracking-wider | 0.05em | Uppercase labels |
tracking-widest | 0.1em | Eyebrow text |
<div class="space-y-4 p-4">
<p class="text-xs font-semibold tracking-widest text-indigo-600 uppercase">Case study</p>
<h2 class="text-4xl font-bold tracking-tight text-gray-900">Typography that reads well</h2>
<p class="max-w-prose leading-relaxed text-gray-600">
Larger text wants tighter tracking and leading. Body copy wants looser leading and a
constrained measure so the eye can find the next line.
</p>
</div>Font features#
v4.2 font-features-* controls font-feature-settings for OpenType features.
<table class='font-features-["tnum"]'>…</table>Tabular numerals keep digits the same width, so figures in a table line up.
Tailwind also ships dedicated numeric utilities:
| Utility | Effect |
|---|---|
tabular-nums | Fixed-width digits |
proportional-nums | Natural digit widths |
slashed-zero | Zero with a slash |
oldstyle-nums | Text figures with descenders |
ordinal | Proper ordinal glyphs (1ˢᵗ) |
Building a type scale#
@import "tailwindcss";
@theme {
--font-display: "Satoshi", ui-sans-serif, sans-serif;
--font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
--text-eyebrow: 0.75rem;
--text-eyebrow--line-height: 1rem;
--text-eyebrow--letter-spacing: 0.1em;
--text-eyebrow--font-weight: 600;
--text-display: clamp(2.5rem, 1.8rem + 3vw, 4.5rem);
--text-display--line-height: 1.05;
--text-display--letter-spacing: -0.03em;
}<p class="text-eyebrow text-indigo-600 uppercase">Introducing</p>
<h1 class="font-display text-display">A scale you only define once</h1>The clamp() makes the display size fluid without a single breakpoint.
Common mistakes#
font-lgortext-bold. It istext-lgandfont-bold. Size istext-*, weight isfont-*, family is alsofont-*.- Setting line height separately when the size already sets it.
text-lg leading-7is fine, buttext-lg/7is clearer. - No fallback stack.
--font-display: "Satoshi"alone leaves nothing to render while the font loads. - Unbounded line length. Body text without
max-w-prose(or similar) becomes unreadable on wide screens. - Using
font-thinfor body copy. 100-weight text at 14px fails contrast expectations for many readers, even when the colour ratio passes.
Related topics#
- Text Styling — colour, alignment, decoration, wrapping
- Theme & Design Tokens — the
--text-*and--font-*namespaces - Plugins — the typography plugin for long-form content