Typography (Heading, Text, Link, Code, Prose)
import { Heading, Link, Text, setLineClamp } from '@absoluteui/components/typography';import '@absoluteui/components/typography/style.css';Using Angular? See Typography (Heading, Text, Link, Code, Prose) for Angular.
What it does
Section titled “What it does”Token-based typography. The CSS classes are the primary API and work without JavaScript: headings, body text, links, inline code, rich-text prose, truncation, and line clamping. The JS helpers create validated elements:
Heading.create: the semantic level (document outline) is independent of the visual size;Text.create: tone, size, and weight modifiers;Link.create: only http(s) and relative destinations; links that open a new tab say so in a localized, visually hidden hint;setLineClamp: a validated line count.
When to use
Section titled “When to use”- Headings, body text, and supporting text that must follow the theme’s type scale.
- Links inside content, including links that open in a new tab.
- Rich text from a CMS or Markdown renderer (aui-prose), after sanitization.
- Truncating long single-line labels or clamping previews to a number of lines.
When not to use
Section titled “When not to use”- Actions that do not navigate: use a Button.
- Code blocks that need syntax highlighting: use a dedicated highlighter inside aui-prose pre.
- Truncating essential information that users cannot otherwise reach.
Examples
Section titled “Examples”Semantic level independent of visual size
Section titled “Semantic level independent of visual size”import { Heading, Text } from '@absoluteui/components/typography';
const section = document.createElement('section');section.append( Heading.create(2, 'Billing', { size: 4 }), Text.create('Invoices are issued on the first of each month.', { tone: 'muted', size: 'sm' }),);document.body.append(section);Link that opens in a new tab
Section titled “Link that opens in a new tab”import { Link } from '@absoluteui/components/typography';
const p = document.createElement('p');p.append('Read the ', Link.create({ href: 'https://example.com/guide', text: 'setup guide', external: true }), '.');document.body.append(p);Clamp a preview to two lines
Section titled “Clamp a preview to two lines”import { setLineClamp } from '@absoluteui/components/typography';
const preview = document.createElement('p');preview.className = 'aui-text';preview.textContent = 'A long description that should show at most two lines in the list view.';document.body.append(preview);const unclamp = setLineClamp(preview, 2);preview.addEventListener('click', unclamp, { once: true });Localize the new-tab hint
Section titled “Localize the new-tab hint”import { configureAbsoluteUI, registerMessages } from '@absoluteui/core';
registerMessages('typography', 'de', { opensInNewTab: '(öffnet in einem neuen Tab)' });configureAbsoluteUI({ components: { typography: { locale: 'de-DE' } } });import { Heading, Link, Text, setLineClamp } from '@absoluteui/components/typography';import '@absoluteui/components/typography/style.css';
const section = document.querySelector<HTMLElement>('#release');if (section) { const summary = Text.create('This release adds layout primitives, cards, and typography helpers across the library.'); section.append(Heading.create(2, 'Release 0.2', { size: 3 }), summary, Link.create({ href: '/changelog', text: 'Full changelog' })); setLineClamp(summary, 2);}More usage
Section titled “More usage”<h2 class="aui-heading aui-heading--4">Billing</h2><p class="aui-text aui-text--muted">Invoices are issued monthly. <a class="aui-link" href="/billing">Manage billing</a></p>import { Heading, Link } from '@absoluteui/components/typography';
document.body.append(Heading.create(2, 'Billing', { size: 4 }), Link.create({ href: 'https://example.com', text: 'Status page', external: true }));Anatomy
Section titled “Anatomy”<h2 class="aui-heading aui-heading--4">Billing</h2> level 2, size 4<p class="aui-text aui-text--muted aui-text--sm">Supporting text</p><a class="aui-link" href target="_blank" rel="noopener noreferrer"> Setup guide<span class="aui-link__hint"> (opens in a new tab)</span> (visually hidden)</a><code class="aui-code">npm install</code><div class="aui-prose"> p, ul, ol, h2-h4, a, code, pre, blockquote </div><span class="aui-truncate">...</span><p class="aui-line-clamp" style="--aui-lines: 2">...</p> (custom property set via the CSSOM)API reference
Section titled “API reference”Factory
Section titled “Factory”Heading.create(level: HeadingLevel, text: string, options?: HeadingOptions, doc?: Document): HTMLHeadingElement; Text.create(text: string, options?: TextOptions, doc?: Document): HTMLParagraphElement | HTMLSpanElement; Link.create(options: LinkOptions, doc?: Document): HTMLAnchorElement; setLineClamp(el: HTMLElement, lines: number): () => voidGlobal configuration key: typography (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
level |
1 | 2 | 3 | 4 | 5 | 6 |
Heading.create: semantic heading level (document outline). Required. | |
size |
1 | 2 | 3 | 4 | 5 | 6 (Heading) | 'xs' | 'sm' | 'md' | 'lg' (Text) |
Heading: visual size, default the level. Text: font size, default md. | |
tone |
'default' | 'muted' |
"default" |
Text: muted uses color-text-muted. |
strong |
boolean |
false |
Text: semibold weight. |
as |
'p' | 'span' |
"p" |
Text: element to create. |
href |
string |
Link: http(s) URL or relative reference; other schemes throw TYPOGRAPHY_OPTIONS. Required. | |
text |
string |
Heading, Text, Link: text content (rendered with textContent). Required. | |
external |
boolean |
false |
Link: target=_blank, rel=“noopener noreferrer”, and a visually hidden localized “(opens in a new tab)”. |
muted |
boolean |
false |
Link: muted color; the underline remains. |
lines |
number |
setLineClamp: integer 1..20, written to –aui-lines. Required. | |
locale |
string |
"en-US" |
Locale of the external-link hint (Link.create option or global). Globally configurable. Inherited from common configuration. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
Heading.enhance(el: HTMLHeadingElement, options?: HeadingOptions): TypographyEnhancement<HeadingOptions> |
Since 0.9.0. Style an existing h1..h6 (level from the tag). |
Text.enhance(el: HTMLElement, options?: TextEnhanceOptions): TypographyEnhancement<TextEnhanceOptions> |
Since 0.9.0. Add aui-text modifiers to an existing element. |
Link.enhance(a: HTMLAnchorElement, options?: LinkEnhanceOptions): TypographyEnhancement<LinkEnhanceOptions> & { check(): void } |
Since 0.9.0. Style and validate an existing link; destroy() restores target and rel. |
isSafeHref(value: unknown): value is string |
The link destination check used by Link and Card. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-heading |
Heading base: semibold, line-height-tight, color-text. |
aui-heading--1 ... aui-heading--6 |
Visual sizes font-size-4xl, 3xl, 2xl, xl, lg, md. |
aui-text |
Body text: font-size-md, line-height-normal. |
aui-text--muted | --lg | --sm | --xs | --strong |
Text modifiers. |
aui-link |
Underlined color-link link with a focus ring; LinkText in forced colors. |
aui-link--muted |
Muted link color, still underlined. |
aui-link__hint |
Visually hidden new-tab hint. |
aui-code |
Inline code: font-family-mono on color-surface-sunken. |
aui-prose |
Rich text rhythm for p, lists, h2 to h4, links, code, pre, and blockquote (line-height-relaxed). |
aui-truncate |
Single-line ellipsis. |
aui-line-clamp |
Multi-line clamp; lines from –aui-lines (default 3). |
--aui-lines |
Custom property: number of lines for aui-line-clamp. |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-border-width-strong | --aui-color-border-strong | --aui-color-focus-ring | --aui-color-link | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-muted | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-mono | --aui-font-family-sans | --aui-font-size-2xl | --aui-font-size-3xl | --aui-font-size-4xl | --aui-font-size-lg | --aui-font-size-md | --aui-font-size-sm | --aui-font-size-xl | --aui-font-size-xs | --aui-font-weight-semibold | --aui-line-height-normal | --aui-line-height-relaxed | --aui-line-height-tight | --aui-radius-md | --aui-radius-sm | --aui-space-1 | --aui-space-2 | --aui-space-4 | --aui-space-6 | --aui-space-8
TypeScript definitions
Section titled “TypeScript definitions”type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;type TextTone = 'default' | 'muted';type TextSize = 'xs' | 'sm' | 'md' | 'lg';interface HeadingOptions { size?: HeadingLevel }interface TextOptions { tone?: TextTone; size?: TextSize; strong?: boolean; as?: 'p' | 'span' }interface LinkOptions { href: string; text: string; external?: boolean; muted?: boolean; locale?: string }declare function setLineClamp(el: HTMLElement, lines: number): () => void;declare function isSafeHref(value: unknown): value is string;Accessibility
Section titled “Accessibility”Pattern: Native HTML text semantics: <h1>-<h6>, <p>, <a href>, <code>. Visual size is decoupled from heading level.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Link | Moves focus to and from the link (native). |
| Enter | Link focused | Follows the link (native). |
| Tab / Shift+Tab | Headings, text, code | Not applicable: not focusable. |
| Element | Role |
|---|---|
| Heading.create | heading (native), level = the level argument |
| Link.create | link (native <a href>) |
| Text.create | paragraph or generic (native <p> / <span>) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
(none) |
external link | No ARIA: the new-tab hint is visually hidden text inside the link, so it is part of the accessible name |
Links show a color-focus-ring outline on :focus-visible (Highlight in forced colors).
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”| Criterion | Level | Note |
|---|---|---|
| 1.3.1 Info and Relationships | A | |
| 1.4.1 Use of Color | A | |
| 1.4.3 Contrast (Minimum) | AA | |
| 1.4.4 Resize Text | AA | |
| 1.4.12 Text Spacing | AA | |
| 2.4.4 Link Purpose (In Context) | A | |
| 2.4.6 Headings and Labels | AA | |
| 2.4.7 Focus Visible | AA | |
| 3.2.5 Change on Request | AAA |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- Links are always underlined, so they are not identified by color alone (WCAG 1.4.1).
- Links that open a new tab say so in their accessible name (WCAG 3.2.5 advisory technique G201).
- Heading level and visual size are independent, so the outline can be correct without compromising the design.
- Truncated or clamped text remains in the DOM, so screen readers read it in full; sighted users need another way to see it.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) of the new-tab hint is pending.
Behavior
Section titled “Behavior”States
Section titled “States”Links: default, hover (thicker underline), focus-visible (focus ring). Text: truncated, clamped.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| unclamped | setLineClamp(el, n) |
clamped to n lines |
| clamped | disposer called | previous classes and --aui-lines restored |
Heading, Text, and Link elements are static once created.
Accessibility notes
Section titled “Accessibility notes”- Links are always underlined, so they are never identified by color alone (WCAG 1.4.1). This includes
--muted. - Choose the heading level for the outline and
sizefor appearance (WCAG 1.3.1, 2.4.6). - Links that open a new tab tell the user in advance (WCAG 3.2.5, technique G201).
- Truncated and clamped text stays in the DOM, so screen readers read it in full. Give sighted users a way to see the full text too.
- Manual screen-reader verification is pending.
Responsive behavior
Section titled “Responsive behavior”All sizes are rem tokens and scale with user font settings (WCAG 1.4.4). Long words wrap (overflow-wrap). aui-truncate needs a constrained inline size, for example a flex child.
Right-to-left
Section titled “Right-to-left”Logical properties throughout: list indentation and the blockquote rule sit at the inline start, and the ellipsis appears at the inline end.
Theming
Section titled “Theming”Colors come from role tokens with verified contrast pairs:
color-linkandcolor-text-mutedoncolor-bgandcolor-surface;color-textoncolor-surface-sunken(code).
In forced-colors mode, links use LinkText and a Highlight focus outline, and inline code keeps a visible border.
Global configuration
Section titled “Global configuration”registerMessages('typography', 'de', { opensInNewTab: '(öffnet in einem neuen Tab)' });configureAbsoluteUI({ components: { typography: { locale: 'de-DE' } } });Component configuration
Section titled “Component configuration”Link.create({ locale }) overrides the global locale for that link. The hint is resolved when the link is created.
None. External links get a text hint for assistive technology, not an icon.
Security
Section titled “Security”- All helpers set text with
textContent. Link.createcheckshrefwith the WHATWG URL parser (the one the browser uses to follow the link). Onlyhttp:,https:, and relative references are accepted.javascript:,data:,vbscript:,file:,blob:, and obfuscated forms (mixed case, leading control characters, embedded tabs or newlines) are rejected.- External links get
rel="noopener noreferrer". setLineClampwrites one custom property through the CSSOM.aui-prosestyles markup but does not sanitize it: pass untrusted HTML through the core sanitizer (setSanitizedHtml) first.- CSP-safe.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. External links send no referrer (noreferrer).
Performance
Section titled “Performance”Each helper creates one element (two for external links) and attaches no listeners or subscriptions. There is no dedicated performance budget yet.
Supported data scale
Section titled “Supported data scale”Not data-driven. aui-prose handles documents of any length; layout cost is the browser’s.
Edge cases
Section titled “Edge cases”Heading.create(2, 'x', { size: 1 })is an<h2>at the largest size.Link.create({ href: 'java\tscript:alert(1)' })throws: the URL parser strips the tab, so the scheme isjavascript:.- Protocol-relative URLs (
//cdn.example.com) are accepted; they resolve to the page’s http(s) scheme. mailto:andtel:are rejected byLink.create; use a plain<a class="aui-link">for them.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
TYPOGRAPHY_OPTIONS |
configuration | Invalid level, size, tone, as, empty text, unsafe href, or line count outside 1..20. |
I18N_MISSING_MESSAGE |
configuration | No opensInNewTab message for the locale chain (English is always registered). |
Invalid calls create nothing and leave elements unchanged.
Known limitations
Section titled “Known limitations”- The external-link hint does not update when the locale changes after creation.
aui-line-clamprelies on-webkit-line-clamp; the standardline-clampis declared for forward compatibility.aui-prosecovers p, ul, ol, li, h2-h4, a, code, pre, and blockquote only.- Manual screen-reader verification is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- HTML strings as heading, text, or link text.
- Non-http(s) schemes in
Link.create. - Fluid (viewport-based) type scales.