Efniv0.1

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.

display

Mission control

h1

Mission MB-4472

h2

Crew assignments

h3

Pre-flight checks

body-lg

Comfortable body copy, for an introduction that needs room.

body

Default body copy. 14px, because this is a data tool.

body-sm

Compact body copy, for dense panels and table captions.

labelLaunch window
data1,024 · 42.3% · MB-4472
eyebrow

Components

eyebrow-lg

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

Renders a td
<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.

Duration00:14:32

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

Do
  • 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
  • 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

PropTypeDefaultDescription
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.
renderReact.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.
…propsuseRender.ComponentProps<"p">—Everything Typography passes to the element it renders.
classNamestring—Merged after the variant classes, so it wins.