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

Utility Classes

Azalea Kit UI ships an optional set of framework-agnostic utility classes for common layout, spacing, typography, and accessibility needs — so app teams don’t hand-roll flex/grid/spacing CSS that drifts from the design tokens.

Every utility on this page ships inside the theme. Load one and you have them all:

<link rel="stylesheet" href="/dist/themes/light.css" />

There is no second stylesheet to add. (utility.css used to be one; it was merged into the themes and removed.)

All classes are prefixed ahi- and reference --ahi-* design tokens, so they track the active theme. Everything lives in the ahi-utilities cascade layer, which means any unlayered CSS in your app overrides these utilities regardless of stylesheet load order — treat them as low-priority defaults you can always override.

:::tip The type and accessibility utilities need no second stylesheet. They ship inside every theme, so ahi-text-body, ahi-text-truncate, ahi-visually-hidden and the rest are available as soon as light.css or dark.css is on the page.

That is deliberate. Some apps embed AKU components and a theme and nothing else — for them, <ahi-text> works today only because its styles ride inside its own shadow root. Its replacement had to reach them the same way. So does everything else on this page. :::

There is no .ahi-stack utility. <div class="ahi-column"> is deprecated — use .ahi-column for a vertical stack or .ahi-row for a horizontal one, with .ahi-gap-* and the alignment classes. Both ship inside the theme, so no extra stylesheet is needed.

Layout primitives

Class What it does
ahi-cluster Inline row that wraps; vertically centered. Buttons, tags, chips, nav links.
ahi-grid Responsive columns with no media queries. Tune the wrap threshold with --ahi-min-column-size (default 20ch).
ahi-flank A fixed-size item beside a flexible one (media object). Set the fixed width with --ahi-flank-size. Add ahi-flank-end to flank the last child instead.
ahi-split Pushes children to opposite ends (toolbars, headers with a trailing action). Add ahi-split-column to stack vertically.
ahi-frame Fixed aspect-ratio box; children cover it. Add ahi-frame-landscape (16:9) or ahi-frame-portrait (9:16); default is square.
<div class="ahi-cluster ahi-gap-2">
  <ahi-button>Save</ahi-button>
  <ahi-button variant="default">Cancel</ahi-button>
</div>

<div class="ahi-grid" style="--ahi-min-column-size: 16rem;">
  <ahi-card>…</ahi-card>
  <ahi-card>…</ahi-card>
  <ahi-card>…</ahi-card>
</div>

<div class="ahi-flank ahi-gap-3" style="--ahi-flank-size: 3rem;">
  <ahi-avatar></ahi-avatar>
  <div>Name and supporting text that fills the remaining space.</div>
</div>

Use ahi-span-grid on a child to make it span the full width of an ahi-grid row.

Spacing

ahi-gap-* sets the gap on any flex or grid container, from the spacing scale (--ahi-space-*): ahi-gap-0, -1, -2, -3, -4, -5, -6, -8, -10, -12, -16.

Alignment

  • Cross-axis: ahi-align-items-start / -end / -center / -stretch / -baseline
  • Main-axis: ahi-justify-content-start / -end / -center / -space-between / -space-around / -space-evenly
  • Wrapping: ahi-flex-wrap / ahi-flex-nowrap

Typography

Available from the theme alone — no second stylesheet. See type roles for what the roles mean and how a density tier moves them.

Roles

A role sets a size and its matching line height together. Pick what the text is, not how big it should be.

Class What it is Example
ahi-text-display Page-level titles. Aa
ahi-text-heading Section titles. Aa
ahi-text-subheading Card and group titles. Aa
ahi-text-body Running text, and most of the UI. Aa
ahi-text-body-emphasis Body, weight-shifted. Same metrics, heavier. Aa
ahi-text-label Form labels, table headers. Aa
ahi-text-caption Help text, timestamps, metadata. Aa
ahi-text-code Monospace, inline and block. Aa

Modifiers

Combine any of these with a role. Each is a single class, so order in the class attribute does not matter.

Group Classes
Color ahi-text-subdued, -critical, -warning, -success, -inherit
Weight ahi-text-regular, -medium, -semibold, -bold
Alignment ahi-text-start, -center, -end, -justify
Transform ahi-text-uppercase, -capitalize
Wrapping ahi-text-truncate (single-line ellipsis), -nowrap, -break-word (breaks long URLs and identifiers), -clamp-2, -clamp-3
Other ahi-text-numeric (tabular figures, so columns of numbers line up), ahi-text-line-through
<p class="ahi-text-body ahi-text-subdued">Last updated 12 minutes ago</p>
<p class="ahi-text-caption ahi-text-critical">This field is required</p>
<p class="ahi-text-body ahi-text-clamp-2">A long note that stops after two lines…</p>

ahi-text-truncate needs a definite width to clip against, and the clamps need the element to be a block — neither forces display, so they keep working on a flex or grid child.

If your app styles h1–h6 globally, those rules win. The utilities live in the ahi-utilities cascade layer, and unlayered CSS beats a layer — which is deliberate, so your app can always override AKU. But it means a rule like h1 { font-size: 2.5rem } overrides .ahi-text-heading on an <h1 class="ahi-text-heading">.

The failure is worse than it sounds, because it is partial: your rule sets font-size but probably not line-height, so the element takes your size and the role’s leading — a mismatched pair, which is the one thing the roles exist to prevent. AKU’s own documentation site hit exactly this.

Exclude elements that opt into a role:

h1:not([class*='ahi-text-']),
h2:not([class*='ahi-text-']) {
  font-size: 2.5rem;
}

Migrating from <ahi-text>

<ahi-text> is being retired. Every one of its properties is plain CSS, so each maps to a class:

<ahi-text> Utility class
variant="heading-3xl" / "heading-2xl" ahi-text-display
variant="heading-xl" / "heading-lg" ahi-text-heading
variant="heading-md" / "heading-sm" ahi-text-subheading or ahi-text-body-emphasis
variant="heading-xs" ahi-text-caption
variant="body-lg" / "body-md" (default) ahi-text-body
variant="body-sm" / "body-xs" ahi-text-caption
color="subdued" | "critical" | "warning" | "success" ahi-text-subdued | -critical | -warning | -success
font-weight="regular" | "medium" | "semibold" | "bold" ahi-text-regular | -medium | -semibold | -bold
alignment="start" | "center" | "end" | "justify" ahi-text-start | -center | -end | -justify
truncate ahi-text-truncate
break-word ahi-text-break-word
numeric ahi-text-numeric
text-decoration="line-through" ahi-text-line-through
visually-hidden ahi-visually-hidden
as="h2" Write the element you want: <h2 class="…">

The variant sizes and the roles are not the same scale, so a few mappings change the rendered size by a pixel or two. body-md — the default when no variant is set — is 13px and becomes 14px as ahi-text-body. Check anywhere the exact size matters.

Available from the theme alone — no second stylesheet. Put ahi-link on an <a> for navigation, or on a <button type="button"> for an action that reads as a link. It takes the surrounding font, so a link inside a sentence matches the sentence and wraps with it.

Class What it does
ahi-link Interactive color, underlined at rest. Inherits the font family, size, weight and line height, with no padding or minimum height. Hover and press follow the interactive tokens, and keyboard focus draws the focus ring.
ahi-link-standalone Add to ahi-link for a link outside a sentence, such as “Back to results” or a list of links. Underlines on hover and keyboard focus instead, and meets the target-size floor: 24px, or 44px on touch and in the comfortable and spacious density tiers.
ahi-link-subdued Add to ahi-link for a secondary link, such as a footer or a caption’s “Learn more”. Text color instead of interactive, still underlined.
ahi-surface-selected Put on a panel, not a link, to paint the selected tint. Links and plain buttons on it move one state along the interactive colors, so they clear 4.5:1 in the light theme (see below).

Your results are ready. Review the lab report from your last visit before your next appointment.

<p class="ahi-text-body" style="max-width: 36ch">
  Your results are ready.
  <a class="ahi-link" href="#">Review the lab report from your last visit</a>
  before your next appointment.
</p>

The same class on a button, for an action in a sentence:

Showing 3 of 12 notes.

<p class="ahi-text-body">Showing 3 of 12 notes. <button type="button" class="ahi-link">Show all</button></p>

Standalone links, out of running text:

<div class="ahi-column ahi-align-items-start ahi-gap-1">
  <a class="ahi-link ahi-link-standalone" href="#">Back to results</a>
  <a class="ahi-link ahi-link-standalone" href="#">Privacy policy</a>
  <a class="ahi-link ahi-link-standalone" href="#">Terms of use</a>
</div>

Subdued, for a link that should not compete with the text around it:

By continuing you agree to the terms of use.

<p class="ahi-text-caption ahi-text-subdued">
  By continuing you agree to the <a class="ahi-link ahi-link-subdued" href="#">terms of use</a>.
</p>

A type role on the link itself sets its size, as it would on any element: ahi-link ahi-text-caption is a caption-sized link.

Links or plain buttons? Use ahi-link when the control sits in or after a sentence. <ahi-button plain> stays for actions that sit beside other buttons, where its sizes, icons and loading state matter. A <button> is an atomic inline box, so a long label wraps inside the button rather than across the paragraph’s lines. Keep button labels short, and use an <a> for anything that navigates.

Links on the selected tint. The standard interactive blue falls just short of 4.5:1 on --ahi-surface-selected in the light theme. When a panel takes that tint, such as a chosen card, a notice or a picked row, paint it with the ahi-surface-selected class rather than setting the background yourself. The class moves its content one state along the interactive colors, as an info banner does: links take the usual hover color at rest and the pressed color on hover. Put the class on the container, not on the link, and put a theme class (ahi-theme-*, ahi-invert) on a wrapper around the panel rather than on the panel itself. On the panel, its tokens undo the shift at rest, and links fall back below 4.5:1. A background set by hand to var(--ahi-surface-selected) gets no shift. A panel inside another shifts once, but a panel and an info banner nested in each other add their shifts together, and hover then stops changing the color.

Tuesday at 9:30 AM is selected. Choose a different time
<div
  class="ahi-surface-selected ahi-text-body"
  style="padding: var(--ahi-space-4); border-radius: var(--ahi-border-radius-medium)"
>
  Tuesday at 9:30 AM is selected. <a class="ahi-link" href="#">Choose a different time</a>
</div>

If your app styles a or button globally, those rules win over ahi-link, for the same cascade-layer reason as the headings above. A global button { padding: 8px 16px } puts the padding back on a button link. Exclude the class:

button:not(.ahi-link) {
  padding: 8px 16px;
}

Accessibility

Available from the theme alone — no second stylesheet.

  • ahi-visually-hidden — hide content visually while keeping it available to assistive technology (revealed when it or a descendant receives focus, so it works for skip links)
  • ahi-visually-hidden-label — applied to a form control, visually hides just its label part while keeping it announced

Preventing flash of undefined elements (FOUCE)

Add ahi-cloak to a container to keep it hidden until it and all of its custom-element descendants are defined — no loader required:

<div class="ahi-cloak">
  <ahi-card>…</ahi-card>
</div>