Typography
Font families, geometric type scale, weight, line-height, and semantic text tokens for consistent, accessible text styling.Overview
Typography is built on a geometric type scale: base size × ratio^step, with 14px and 1.2 as defaults. Every text style is a semantic token that composes font size, weight, and line-height, so components express intent (heading, body, label) rather than raw values.Two layers work together: raw size tokens (--font-size-xs ... --font-size-5xl) form the geometric scale, and semantic type scale tokens (--text-heading-1-size, --text-body-leading, etc.) reference them by var(). Themes override the entire scale by adjusting base and ratio in defineTheme; all semantic tokens recompute automatically.Font Families
Three font roles: body (UI text), heading (titles and headings), and code (monospace). By default, body and heading share the same system font stack; code uses a monospace stack. Custom themes can assign different families per role; heading inherits from body when not explicitly set.| Token | Value | Example |
|---|---|---|
| --font-family-body | var(--font-figtree,Figtree) | The quick brown fox jumps over the lazy dog |
| --font-family-code | "SF Mono" | The quick brown fox jumps over the lazy dog |
| --font-family-heading | var(--font-figtree,Figtree) | The quick brown fox jumps over the lazy dog |
Font Sizes
Geometric scale: round(base × ratio^step), expressed in rem. The default scale is 14px × 1.2, producing 12 steps from 4xs (6px) to 5xl (42px). Adjusting base and ratio in defineTheme regenerates every size token while preserving proportional relationships.| Token | Value | Example |
|---|---|---|
| --font-size-4xs | 0.375rem | The quick brown fox jumps over the lazy dog |
| --font-size-3xs | 0.4375rem | The quick brown fox jumps over the lazy dog |
| --font-size-2xs | 0.5rem | The quick brown fox jumps over the lazy dog |
| --font-size-xs | 0.625rem | The quick brown fox jumps over the lazy dog |
| --font-size-sm | 0.75rem | The quick brown fox jumps over the lazy dog |
| --font-size-base | 0.875rem | The quick brown fox jumps over the lazy dog |
| --font-size-lg | 1.0625rem | The quick brown fox jumps over the lazy dog |
| --font-size-xl | 1.25rem | The quick brown fox jumps over the lazy dog |
| --font-size-2xl | 1.5rem | The quick brown fox jumps over the lazy dog |
| --font-size-3xl | 1.8125rem | The quick brown fox jumps over the lazy dog |
| --font-size-4xl | 2.1875rem | The quick brown fox jumps over the lazy dog |
| --font-size-5xl | 2.625rem | The quick brown fox jumps over the lazy dog |
Font Weights
Four semantic weights: normal (400, body/code), medium (500, labels/data), semibold (600, headings/titles), bold (700, strong emphasis). Type scale tokens reference these by var() so themes can remap numeric values.| Token | Value | Example |
|---|---|---|
| --font-weight-normal | 400 | The quick brown fox jumps over the lazy dog |
| --font-weight-medium | 500 | The quick brown fox jumps over the lazy dog |
| --font-weight-semibold | 600 | The quick brown fox jumps over the lazy dog |
| --font-weight-bold | 700 | The quick brown fox jumps over the lazy dog |
Line Height
Line heights are computed from a tiered target ratio and snapped to a 4px vertical grid. Small text (<20px) targets 1.5, medium text (20–31px) targets 1.4, and large text (≥32px) targets 1.25. A minimum gap of fontSize + 4px is enforced. The result is a unitless ratio stored in each --text-*-leading token.The 4px grid matters: every line box aligns to 4px increments, which keeps baselines, spacing, and component heights predictable. The expandTypeScale utility computes these automatically when you provide a base and ratio, so you should never need to set line-height manually.Type Scale
Semantic tokens that combine size, weight, and line-height into a single type style. Each token triplet (--text-*-size, --text-*-weight, --text-*-leading) is consumed by Text and Heading. Use the component props rather than composing raw font tokens.| Sample | Tokens |
|---|---|
| H1 | var(--font-size-2xl) · var(--font-figtreevar(--font-weight-semibold) · 1.3333 |
| H2 | var(--font-size-xl) · var(--font-figtreevar(--font-weight-semibold) · 1.4 |
| H3 | var(--font-size-lg) · var(--font-figtreevar(--font-weight-semibold) · 1.4118 |
| H4 | var(--font-size-base) · var(--font-figtreevar(--font-weight-semibold) · 1.4286 |
| H5 | var(--font-size-sm) · var(--font-figtreevar(--font-weight-semibold) · 1.6667 |
| H6 | var(--font-size-xs) · var(--font-figtreevar(--font-weight-semibold) · 1.6 |
| Display 1 | var(--font-size-5xl) · var(--font-figtreevar(--font-weight-semibold) · 1.2381 |
| Display 2 | var(--font-size-4xl) · var(--font-figtreevar(--font-weight-semibold) · 1.2571 |
| Display 3 | var(--font-size-3xl) · var(--font-figtreevar(--font-weight-semibold) · 1.2414 |
| Large | var(--font-size-lg) · var(--font-figtreevar(--font-weight-semibold) · 1.4118 |
| Body | var(--font-size-base) · var(--font-figtreevar(--font-weight-normal) · 1.4286 |
| Label | var(--font-size-base) · var(--font-figtreevar(--font-weight-medium) · 1.4286 |
| Code | var(--font-size-base) · "SF Mono"var(--font-weight-normal) · 1.4286 |
| Supporting | var(--font-size-sm) · var(--font-figtreevar(--font-weight-normal) · 1.6667 |
Display Text
Display variants (display-1, display-2, display-3) continue the geometric progression above heading-1, at steps +6, +5, and +4. They use normal weight (400) instead of semibold, and tighter line-heights (~1.2), since large text reads better with less leading. Use display types for hero banners, marketing headlines, and data callouts, not for document headings.Display text often needs heading semantics for accessibility. Use the type prop on Heading to apply display styling while preserving the correct HTML element: <Heading level={1} type="display-1"> gives you display-1 styling with an <h1> tag, so screen readers see the correct document outline.Usage
Heading for document structure
tsximport {Heading} from '@astryxdesign/core';// Heading levels map to semantic tokens: level 1 → --text-heading-1-*<Heading level={1}>Page Title</Heading><Heading level={2}>Section</Heading><Heading level={3}>Subsection</Heading>// Display type for hero/marketing headings — level sets the HTML element<Heading level={1} type="display-1">Hero Title</Heading><Heading level={2} type="display-2">$1.2M Revenue</Heading>// Override the accessibility level when visual ≠ document hierarchy<Heading level={2} accessibilityLevel={3}>Sidebar Section</Heading>
Text for body, label, and display text
tsximport {Text} from '@astryxdesign/core';<Text type="body">Body text at the base scale.</Text><Text type="large">Emphasized body text.</Text><Text type="label">Form label</Text><Text type="supporting">Helper text, timestamps, metadata.</Text><Text type="code">{'const x = 1;'}</Text>// Display without heading semantics (data callouts, decorative)<Text type="display-2">$1.2M Revenue</Text>
Customizing the type scale via defineTheme
tsximport {defineTheme} from '@astryxdesign/core';// Adjust the entire ramp holistically with base and ratioconst editorialTheme = defineTheme({name: 'editorial',typography: {scale: { base: 16, ratio: 1.25 }, // airy / article feelbody: { family: 'Geist', fallbacks: '-apple-system, sans-serif' },heading: { weight: 'bold' },code: { family: 'Geist Mono', fallbacks: '"SF Mono", monospace' },},});const denseTheme = defineTheme({name: 'dense',typography: {scale: { base: 12, ratio: 1.125 }, // compact / data-dense UI},});
Best Practices
| Guidance | Practices |
|---|---|
| Do | Use Heading for document headings and Text for everything else; they apply the full type scale automatically. |
| Do | Adjust typography holistically: change base and ratio in defineTheme to shift the entire ramp (e.g. { base: 16, ratio: 1.25 } for editorial, { base: 12, ratio: 1.125 } for dense UI). |
| Do | Use display types with as="h1" (or h2/h3) when display text is a page heading; this preserves accessibility while giving you display-level sizing. Or better, use <Heading level={1} type="display-1"> which handles both semantics and styling. |
| Do | Let line-height snap to the 4px grid via the type scale; expandTypeScale computes leading automatically from base and ratio. |
| Do | Use the supporting type for secondary information: timestamps, helper text, metadata, captions. |
| Do | Use accessibilityLevel on Heading when the visual hierarchy doesn't match the document outline (e.g. sidebar or card headings). |
| Don't | Set font-size or line-height manually; use the semantic type scale tokens so the full ramp stays consistent and 4px-grid-aligned. |
| Don't | Skip heading levels (e.g. h1 to h3); screen readers rely on an unbroken hierarchy. Use accessibilityLevel to decouple visual from semantic level. |
| Don't | Use display types for body content or in-page sections; they're designed for hero/marketing/data-callout contexts only. |
| Don't | Override individual size tokens (--font-size-lg) to "tweak" a heading; adjust base/ratio instead so proportions remain coherent across the entire scale. |
| Don't | Use raw numeric font-weight values (400, 600); reference the semantic weight tokens so themes can remap them. |