Changelog Azalea Kit UI 101 Usage Customizing Utilities Form controls Laravel Vue FHIR Types Accessibility Icons Actions Button Button group Layout and structure Card Card section Care summary Care timeline Divider Empty state Footer Header Layout Stack Table Selection and input Calendar Checkbox Checkbox group Color picker Combobox Combobox option Input Input mask Memorable date Number input Option Phone input Radio Radio button Radio group Range Select SSN input Tag Textarea Toggle ZIP code input Images and icons Avatar Icon Icon button Logo Feedback indicators Badge Banner Progress bar Skeleton Skeleton body text Skeleton display text Skeleton thumbnail Spinner Typography Text Navigation Breadcrumb Breadcrumb item Dropdown Menu Menu item Menu label Navigation Nav group Nav item Nav toggle Pagination Tab Tab group Tab panel Top bar Tree Tree item User menu Overlays Dialog Popover Tooltip Utilities Collapsible FHIR address FHIR human name FHIR quantity FHIR questionnaire Format bytes Format date Format number Relative time Resize observer Split panel Tooltip Border Color Shadow Spacing Transition Typography Z-index Contributing Visual Tests Light Dark System

Typography

Typography tokens are used to maintain a consistent set of font styles throughout our apps.

Font family

The default font stack is designed to be simple and highly available on as many devices as possible.

Token Value Example
--ahi-font-family-sans -apple-system, BlinkMacSystemFont, ‘Segoe UI’, Roboto, Helvetica, Arial, sans-serif, ‘Apple Color Emoji’, ‘Segoe UI Emoji’, ‘Segoe UI Symbol’ The quick brown fox jumped over the lazy dog.
--ahi-font-family-mono SFMono-Regular, Consolas, ‘Liberation Mono’, Menlo, monospace; The quick brown fox jumped over the lazy dog.

Type roles

A role is what the text is — running text, a form label, a timestamp — rather than how big it is. Each one is a size and the leading it is meant to be set on, published as a pair: --ahi-type-<role>-font-size and --ahi-type-<role>-line-height.

Reach for a role first. The numeric scale below still exists and still works, but it asks you to make two decisions that belong together, and the library has the scars to show for it: 14 distinct size/line-height combinations, 14px set against four different line heights, and 15px set inside a 16px line box — which is how a component shipped clipping its own descenders. A role gives you the pair, already checked.

Role What it is Compact Example
display Page-level titles. 30 / 36 Aa
heading Section titles. 20 / 28 Aa
subheading Card and group titles. 16 / 24 Aa
body Running text, and most of the UI. 14 / 20 Aa
body-emphasis Body, weight-shifted. Same metrics; differs by weight alone. 14 / 20 Aa
label Form labels, table headers. 14 / 20 Aa
caption Help text, timestamps, metadata. 12 / 16 Aa
code Monospace, inline and block. 13 / 20 Aa

The body-emphasis role carries body’s metrics deliberately — it differs by weight alone. Apply --ahi-font-weight-semibold alongside it.

Density decides the size

The values above are the compact tier: clinical density, which is the default. Type size is keyed on who is reading, not on how wide the window is — a clinician’s phone wants the densest text in the system, and a clinic kiosk on a large screen wants the largest.

Role Compact
clinical — EHR, MyPractice
Comfortable
patient-facing — portal, forms
Spacious
kiosk — read standing, at arm’s length
display 30 / 36 34 / 40 36 / 44
heading 20 / 28 24 / 32 30 / 36
subheading 16 / 24 18 / 26 20 / 28
body 14 / 20 16 / 24 18 / 28
body-emphasis 14 / 20 16 / 24 18 / 28
label 14 / 20 16 / 24 18 / 28
caption 12 / 16 14 / 20 16 / 24
code 13 / 20 14 / 22 16 / 24

Setting the tier

Not every app owns its <body>, so a tier can be applied at whichever level you actually control. Custom properties inherit — including across the shadow boundary — so all three work with no extra machinery, and a tier scopes to its subtree: a dense table inside a comfortable page can opt back out.

The whole app, when you control the document:

<html class="ahi-density-comfortable"></html>

One region, inside a shell you do not own:

<div class="ahi-density-comfortable">...</div>

A single component, when you own nothing else. Set the role tokens directly — a class cannot reach a component’s internals, but an inherited custom property can:

<ahi-card
  style="
    --ahi-type-subheading-font-size: 18px;
    --ahi-type-subheading-line-height: 26px;
  "
>
  ...
</ahi-card>

Compact is the default and has no class — applying nothing changes nothing.

Set a tier as high up as you can. Overriding role tokens on a single component pins that component to one size — it stops responding to the tier around it, which is the behavior the tiers exist to provide.

Scaling with a user’s text-size preference

--ahi-font-scale multiplies the roles exactly as it multiplies the numeric scale, sizes and line heights together. It must be set on :root to take effect: CSS substitutes a var() inside a custom property’s value at the element where that property is declared, so setting the scale further down the tree cannot reach back into a role.

:root {
  --ahi-font-scale: 1.35;
}

Font size

Eight steps. Prefer a type role — a role pairs a size with the leading it is meant to be set on, and a raw step is a size with no opinion about the line box it sits in.

Token Value Example
--ahi-font-size-300 12px Aa
--ahi-font-size-350 14px Aa
--ahi-font-size-400 16px Aa
--ahi-font-size-450 18px Aa
--ahi-font-size-500 20px Aa
--ahi-font-size-600 24px Aa
--ahi-font-size-750 30px Aa
--ahi-font-size-900 36px Aa

Retired steps

There were fifteen, eight of them a single pixel from their neighbor, and nothing said which of a pair to reach for — which is how <ahi-checkbox> came to render its label at 15px while <ahi-radio> rendered the same label at 14px.

These seven still resolve, so nothing breaks on upgrade, but they are deprecated and will be removed in the next major. Each folds to the survivor a type role already sits on rather than to the arithmetic nearest, because four of them sit exactly between two survivors.

Retired Was Now resolves to
--ahi-font-size-275 11px --ahi-font-size-300 (12px) the caption role
--ahi-font-size-325 13px --ahi-font-size-350 (14px) the body role
--ahi-font-size-375 15px --ahi-font-size-350 (14px) the label role
--ahi-font-size-425 17px --ahi-font-size-400 (16px) the subheading role
--ahi-font-size-550 22px --ahi-font-size-600 (24px) —
--ahi-font-size-800 32px --ahi-font-size-750 (30px) the display role
--ahi-font-size-1000 40px --ahi-font-size-900 (36px) —

Font weight

Token Value Example
--ahi-font-weight-regular 400 The quick brown fox jumped over the lazy dog.
--ahi-font-weight-medium 500 The quick brown fox jumped over the lazy dog.
--ahi-font-weight-semibold 600 The quick brown fox jumped over the lazy dog.
--ahi-font-weight-bold 700 The quick brown fox jumped over the lazy dog.

:::tip These were 450 / 550 / 650 / 700 before this release. On a variable font — macOS resolves the stack to SF Pro — those are four distinct weights, so the scale looked correct. On a static family it collapses: CSS font matching walks available faces upward for any request above 500, so against Windows’ Segoe UI, 550 landed on Semibold and 650 landed on Bold. semibold and bold painted the same weight on the platform most clinicians use. 500 is safe where 550 was not, because a request at or below 500 searches downward instead. :::

Letter spacing

Token Value Example
--ahi-letter-spacing-densest -0.54px The quick brown fox jumped over the lazy dog.
--ahi-letter-spacing-denser -0.3px The quick brown fox jumped over the lazy dog.
--ahi-letter-spacing-dense -0.2px The quick brown fox jumped over the lazy dog.
--ahi-letter-spacing-normal 0px The quick brown fox jumped over the lazy dog.

Line height

Token Value Example
--ahi-line-height-300 12px
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
--ahi-line-height-400 16px
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
--ahi-line-height-500 20px
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
--ahi-line-height-600 24px
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
--ahi-line-height-700 28px
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
--ahi-line-height-800 32px
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
--ahi-line-height-1000 40px
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
--ahi-line-height-1200 48px
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.
The quick brown fox jumped over the lazy dog.