Typography
Airframe styles semantic elements by default and provides a small set of text roles for when semantics and visuals diverge.
This page covers the philosophy, tokens, and every class from typography.css. For utility tweaks (muted, wrap, numeric, alignment helpers), see Typography utilities.
Philosophy
Section titled “Philosophy”- Semantic first:
<h1>–<h6>,<p>,<small>look good by default. Use semantic elements by default. - Text roles only for visual hierarchy overrides: Use
af-text-h*oraf-text-bodyonly when semantics and visuals must diverge.- ✅
<h2 class="af-text-h1">— visually H1, semantically H2 - ✅
<p class="af-text-caption">— caption styling on paragraph - ❌
<h1 class="af-text-h1">— redundant, use<h1>instead
- ✅
- Token-driven: Override
--af-font-*and--af-type-*in your stylesheet — same CSS-variable model as Theming. No rebuild.
Brand your type
Section titled “Brand your type”Fonts and scale are CSS variables. Start here:
:root {
--af-font-primary: 'Inter', system-ui, sans-serif;
--af-font-heading: 'Inter', system-ui, sans-serif;
--af-font-body: var(--af-font-primary);
--af-text-lg: 1.125rem;
}Light, dark, and high-contrast themes do not require separate font setups unless you want them. Full token lists: Tokens full list.
Semantic defaults
Section titled “Semantic defaults”These elements are styled automatically — no classes required:
Title
Section
Subsection
Minor heading
Label heading
Fine heading
Body text
Caption<h1>Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
<h4>Minor heading</h4>
<h5>Label heading</h5>
<h6>Fine heading</h6>
<p>Body text</p>
<small>Caption</small>Heading groups
Section titled “Heading groups”Use <hgroup> to visually group a heading with its subtitle or tagline:
Page Title
Subtitle or tagline text
<hgroup>
<h1>Page Title</h1>
<p class="af-lead">Subtitle or tagline text</p>
</hgroup><hgroup> provides visual grouping only. Keep your heading hierarchy (<h1>–<h6>) correct for accessibility.
Default rhythm
Section titled “Default rhythm”Headings, paragraphs, lists, blockquotes, and dividers include sensible spacing by default. You should rarely need manual spacing for typical long-form content.
Text roles
Section titled “Text roles”Use when semantics and appearance need to diverge. Every role:
Text H1
Text H2
Text H3
Text H4
Text H5
Text H6
Body role
Body small
Caption
Text sm (same size as caption)
Overline<div class="af-text-display">Display</div>
<p class="af-text-h1">Text H1</p>
<p class="af-text-h2">Text H2</p>
<p class="af-text-h3">Text H3</p>
<p class="af-text-h4">Text H4</p>
<p class="af-text-h5">Text H5</p>
<p class="af-text-h6">Text H6</p>
<p class="af-text-body">Body role</p>
<p class="af-text-body-sm">Body small</p>
<p class="af-text-caption">Caption</p>
<p class="af-text-sm">Text sm (same size as caption)</p>
<span class="af-text-overline">Overline</span>| Class | Role |
|---|---|
af-text-display | Hero / marketing display |
af-text-h1 … h6 | Visual heading step without changing outline |
af-text-body | Explicit body role |
af-text-body-sm | Body weight and leading, smaller size |
af-text-caption / af-text-sm | Caption / fine print |
af-text-overline | Uppercase label with letter-spacing |
Lead and eyebrow
Section titled “Lead and eyebrow”Lead — larger intro, muted.
Eyebrow label
Eyebrow on primary
<p class="af-lead">Lead — larger intro, muted.</p>
<p class="af-eyebrow">Eyebrow label</p>
<p class="af-eyebrow af-is-on-primary" style="background: var(--af-color-primary); padding: 0.5rem 0.75rem; border-radius: var(--af-radius);">Eyebrow on primary</p>af-lead— larger intro copy, muted coloraf-eyebrow— uppercase section labelaf-eyebrow.af-is-on-primary— readable on a primary surface
Fluid headings and stats
Section titled “Fluid headings and stats”Fluid H1
Fluid H2
Fluid H3
12.4k
<p class="af-text-fluid-h1">Fluid H1</p>
<p class="af-text-fluid-h2">Fluid H2</p>
<p class="af-text-fluid-h3">Fluid H3</p>
<p class="af-stat-display">12.4k</p>af-text-fluid-h1,af-text-fluid-h2,af-text-fluid-h3— clamp-based hero headingsaf-stat-display— large hero numbers
Still pair marketing type with a real heading in the outline when SEO and assistive tech need one.
Readable line length with line-height: 1lh:
af-prose — 65ch. Comfortable for articles and long paragraphs.
af-prose-narrow — 45ch. Short asides and callouts.
af-prose-wide — 80ch. Leads and wider marketing copy.
<p class="af-prose">af-prose — 65ch. Comfortable for articles and long paragraphs.</p>
<p class="af-prose-narrow">af-prose-narrow — 45ch. Short asides and callouts.</p>
<p class="af-prose-wide">af-prose-wide — 80ch. Leads and wider marketing copy.</p>| Class | Max width |
|---|---|
af-prose | 65ch |
af-prose-narrow | 45ch |
af-prose-wide | 80ch |
Use one class — prefer af-prose-wide alone, not af-prose af-prose-wide.
Blockquote
Section titled “Blockquote”Native <blockquote> and af-blockquote:
Quoted statement with default blockquote styling.
Same look with an explicit class when you need it.
<blockquote>
<p>Quoted statement with default blockquote styling.</p>
</blockquote>
<blockquote class="af-blockquote">
<p>Same look with an explicit class when you need it.</p>
</blockquote>Inline code
Section titled “Inline code”<code> outside a <pre> is styled automatically:
Use af-prose for readable line length.
<p>
Use
<code>af-prose</code>
for readable line length.
</p>Code blocks use the Code Block pattern.
Color and size helpers
Section titled “Color and size helpers”These live in utilities, but show up often with type roles:
Muted
Strong
Monospace
Title helper
Text md
Text lg
On primary
On primary muted
<p class="af-text-muted">Muted</p>
<p class="af-text-strong">Strong</p>
<p class="af-text-mono">Monospace</p>
<p class="af-title">Title helper</p>
<p class="af-text-md">Text md</p>
<p class="af-text-lg">Text lg</p>
<p class="af-text-on-primary" style="background: var(--af-color-primary); padding: 0.5rem 0.75rem; border-radius: var(--af-radius);">On primary</p>
<p class="af-text-on-primary-muted" style="background: var(--af-color-primary); padding: 0.5rem 0.75rem; border-radius: var(--af-radius);">On primary muted</p>Full utility lists: Text style, Text wrap, Text align, Numeric.
Text alignment
Section titled “Text alignment”Dir-aware utilities (start / end follow LTR and RTL):
Centered
Start-aligned
End-aligned
Center, then start from md
<p class="af-text-center">Centered</p>
<p class="af-text-start">Start-aligned</p>
<p class="af-text-end">End-aligned</p>
<p class="af-text-h4 af-text-center af-text-start@md">Center, then start from md</p>Responsive variants: af-text-center@{bp}, af-text-start@{bp}, af-text-end@{bp}. Details: Text alignment.
Token model
Section titled “Token model”Font families
Section titled “Font families”:root {
--af-base-font-sans: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
--af-base-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--af-font-primary: var(--af-base-font-sans);
--af-font-heading: var(--af-font-primary);
--af-font-body: var(--af-base-font-sans);
--af-font-code: var(--af-base-font-mono);
--af-font-mono: var(--af-base-font-mono);
}Type scale
Section titled “Type scale”:root {
--af-text-xs: 0.75rem;
--af-text-sm: 0.875rem;
--af-text-md: 1rem;
--af-text-lg: 1.125rem;
--af-text-xl: 1.25rem;
--af-text-2xl: 1.5rem;
--af-text-3xl: 1.875rem;
--af-leading-tight: 1.1;
--af-leading-normal: 1.5;
--af-leading-loose: 1.7;
--af-weight-regular: 400;
--af-weight-medium: 500;
--af-weight-semibold: 600;
--af-weight-bold: 700;
--af-type-h1-size: var(--af-text-3xl);
--af-type-h1-weight: var(--af-weight-semibold);
--af-type-h1-leading: var(--af-leading-tight);
--af-type-h1-tracking: -0.02em;
}Role tokens (--af-type-h*, tracking, body/caption) are listed in full on Tokens full list.
Example: card title with visual override
Section titled “Example: card title with visual override”Card Title
Body text remains semantic and readable.
<div class="af-card">
<h3 class="af-text-h2">Card Title</h3>
<p class="af-card__body">Body text remains semantic and readable.</p>
</div>Best practices
Section titled “Best practices”- Prefer semantic elements (
<h1>–<h6>,<p>,<small>) by default. - Use text roles only when you need visual hierarchy overrides.
- Override typography via tokens, not by increasing selector specificity.
Browse typography on the patterns gallery. Utilities: Typography utilities.