Components
Typography
The type scale as a component. One element per variant, sized from the --font-size-* tokens, so a heading's look and its place in the document outline stay separate decisions.
When to usewhen you want the type scale without memorising which token, family and weight go together — or when a heading's visual size and its semantic level need to differ. Plain `h1`–`h6` and `p` already inherit the right family from the base layer, so reach for those when the default is what you want.
Import
import { Typography } from "@ravnhq/efni/typography"The scale
Eleven variants, one per size token. Each renders a sensible element by default.
Mission control
Mission MB-4472
Crew assignments
Pre-flight checks
Comfortable body copy, for an introduction that needs room.
Default body copy. 14px, because this is a data tool.
Compact body copy, for dense panels and table captions.
Components
Foundations
<Typography variant="display">Mission control</Typography>
<Typography variant="h1">Mission MB-4472</Typography>
<Typography variant="body">Default body copy.</Typography>
<Typography variant="data">1,024 · 42.3%</Typography>
<Typography variant="eyebrow">Components</Typography>Changing the element
render swaps the tag without touching the type styles — a page's second section can look like an h2 while staying an h3 in the outline.
A real h2
Looks like h2, is an h3
<Typography variant="h2">A real h2</Typography>
{/* same styles, different place in the outline */}
<Typography variant="h2" render={<h3 />}>Looks like h2, is an h3</Typography>Tone
One tone per --color-text-* token, so the prop cannot drift from the token layer. Two of those tokens — tertiary and brand — have no shadcn utility, which is the main reason this axis exists.
inherit — takes whatever colour the context sets (default)
primary — --color-text-primary
secondary — --color-text-secondary
tertiary — --color-text-tertiary
brand — --color-text-brand
<Typography variant="h2" tone="primary">Crew assignments</Typography>
<Typography variant="body-sm" tone="secondary">Cleared at 09:12 UTC</Typography>
<Typography variant="label" tone="tertiary">Disabled field</Typography>
<Typography variant="body" tone="brand">Read the handbook</Typography>Tones for filled surfaces
on-accent, on-status and on-inverse are for text sitting on a coloured fill. Most of the time the surface's own component already sets the colour, so inherit is the right default.
On the brand accent
On the inverse surface
<div className="bg-primary p-3">
<Typography variant="body-sm" tone="on-accent">On the brand accent</Typography>
</div>In context
Mission
Refuel pass, launch pad 3
Cleared by OP-0142 during the 09:12 UTC window.
Do & don't
Crew assignments
MB-4472 · 42.3%Numbers and IDs use the data variant, so they line up in a column and read as data.
Crew assignments
MB-4472 · 42.3%
Body copy for an ID loses tabular alignment and the mono family that marks it as data.
Guidelines
- Let the variant pick the element, and use render only when the outline needs a different level.
- Use data for anything that aligns in a column — counts, rates, IDs, durations.
- Reach for tone rather than a colour class — it is the only way to get tertiary and brand without an arbitrary value.
- Don't reach for Typography when a plain h2 or p already gives you the default — the base layer styles them.
- Don't skip heading levels to get a size; that is what render exists for.
- Don't override the font size with a one-off class — if a size is missing, it belongs in the token scale.
- Don't use className="text-primary" for primary text: with the bridge that utility is the brand colour, not the text-primary token.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "display" | "h1" | "h2" | "h3" | "body-lg" | "body" | "body-sm" | "label" | "data" | "eyebrow" | "eyebrow-lg" | "body" | Type style, one per --font-size-* token. Also sets the default element and the data-variant attribute. |
tone | "inherit" | "primary" | "secondary" | "tertiary" | "brand" | "on-accent" | "on-status" | "on-inverse" | "inherit" | Text colour, one per --color-text-* token. Defaults to inherit so the component never fights a coloured surface. |
render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | — | Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render. |
…props | useRender.ComponentProps<"p"> | — | Everything Typography passes to the element it renders. |
className | string | — | Merged after the variant classes, so it wins. |