Tooltip
import { Tooltip } from '@absoluteui/components/tooltip';import '@absoluteui/components/tooltip/style.css';Using Angular? See Tooltip for Angular.
What it does
Section titled “What it does”A short text hint for a trigger, meeting WCAG 1.4.13 (Content on Hover or Focus). It shows after a delay on pointer hover and immediately on keyboard focus. The pointer can move onto it (hoverable), it stays visible while the trigger is hovered or focused (persistent), and Escape hides it without moving focus (dismissible). The trigger references it through aria-describedby, or through aria-labelledby for icon-only controls. Only one tooltip is visible at a time.
When to use
Section titled “When to use”- Supplementary hints: keyboard shortcuts, the full text of a truncated label, the purpose of an icon-only button.
- Naming an icon-only control visually as well as programmatically (relation ‘label’).
When not to use
Section titled “When not to use”- Essential information or instructions: touch users never see tooltips; put it on the page.
- Interactive content (links, buttons): use Popover.
- Validation errors: use the field’s validation message.
- Long text: tooltips are capped at tooltip-max-width; use Popover or inline help.
Examples
Section titled “Examples”Keyboard shortcut hint
Section titled “Keyboard shortcut hint”import { Tooltip } from '@absoluteui/components/tooltip';import { Button } from '@absoluteui/components/button';
const save = document.createElement('button');save.type = 'button';save.textContent = 'Save';Button.enhance(save);document.body.append(save);Tooltip.create(save, { content: 'Ctrl+S' });Name an icon-only button
Section titled “Name an icon-only button”import { Tooltip } from '@absoluteui/components/tooltip';import { Button } from '@absoluteui/components/button';
const settings = document.createElement('button');settings.type = 'button';document.body.append(settings);// The tooltip names the icon-only button (aria-labelledby), so create it before the Button.Tooltip.create(settings, { content: 'Settings', relation: 'label', placement: 'bottom' });Button.enhance(settings, { icon: 'menu', variant: 'ghost' });Global delays
Section titled “Global delays”import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { tooltip: { showDelay: 300, hideDelay: 200 } } });import { Tooltip } from '@absoluteui/components/tooltip';import '@absoluteui/components/tooltip/style.css';
for (const el of document.querySelectorAll<HTMLElement>('[data-hint]')) { Tooltip.create(el, { content: el.dataset.hint ?? '', placement: 'bottom' });}More usage
Section titled “More usage”import { Tooltip } from '@absoluteui/components/tooltip';
const save = document.querySelector<HTMLButtonElement>('#save');if (save) Tooltip.create(save, { content: 'Ctrl+S' });Anatomy
Section titled “Anatomy”<button aria-describedby=tooltip>Save</button> (consumer trigger)...<div class="aui-tooltip" role="tooltip" popover="manual">Ctrl+S</div> (end of body, or the trigger's <dialog>)API reference
Section titled “API reference”Factory
Section titled “Factory”Tooltip.create(trigger: HTMLElement, options: TooltipOptions): TooltipGlobal configuration key: tooltip (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
content |
string |
Tooltip text (text only). Required. | |
relation |
'description' | 'label' |
"description" |
Trigger gets aria-describedby (‘description’) or aria-labelledby (‘label’, for icon-only controls). |
placement |
Placement |
"top" |
Preferred side and logical alignment; flips and shifts to fit. Globally configurable. |
showDelay |
integer (0..5000) |
500 |
Hover delay before showing, ms. Keyboard focus shows immediately. Globally configurable. |
hideDelay |
integer (0..5000) |
100 |
Delay after the pointer leaves the trigger and tooltip before hiding, ms. Globally configurable. |
direction |
'ltr' | 'rtl' |
"ltr" |
Resolves logical start/end placements. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
element |
HTMLDivElement |
The tooltip (div.aui-tooltip[role=tooltip]). |
trigger |
HTMLElement |
The trigger element. |
isVisible |
boolean |
Whether the tooltip is visible. |
options |
Readonly<TooltipOptions> |
Current options. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
show(): void |
Show immediately (hides any other visible tooltip). |
hide(): void |
Hide immediately. |
update(options: Partial<TooltipOptions>): void |
Merge and apply options (content, relation, placement, delays). |
destroy(): void |
Hide; remove the element, the trigger ARIA reference, listeners, and subscriptions. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-open |
null |
No | No | After the tooltip became visible (dispatched on the tooltip element). |
aui-close |
null |
No | No | After the tooltip was hidden. |
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-tooltip |
Tooltip element (manual popover, top layer). |
aui-tooltip--static |
Set when animation is disabled globally. |
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-color-inverse | --aui-color-on-inverse | --aui-duration-fast | --aui-easing-standard | --aui-font-family-sans | --aui-font-size-sm | --aui-line-height-tight | --aui-radius-sm | --aui-shadow-md | --aui-space-1 | --aui-space-2 | --aui-tooltip-max-width
TypeScript definitions
Section titled “TypeScript definitions”type TooltipRelation = 'description' | 'label';interface TooltipConfig { placement: Placement; showDelay: number; hideDelay: number }interface TooltipOptions extends Partial<TooltipConfig> { content: string; relation?: TooltipRelation; direction?: 'ltr' | 'rtl' }Accessibility
Section titled “Accessibility”Pattern: WAI-ARIA APG Tooltip pattern, with WCAG 1.4.13 Content on Hover or Focus.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Focus moves to the trigger (keyboard focus-visible) | Shows the tooltip immediately. |
| Tab / Shift+Tab | Focus leaves the trigger | Hides the tooltip. |
| Escape | Tooltip visible | Hides the tooltip without moving focus; the key is consumed. |
| Escape | No tooltip visible | Not handled; reaches enclosing overlays and the page. |
| Element | Role |
|---|---|
| tooltip div | tooltip |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-describedby |
trigger | id of the tooltip, added to existing ids (relation ‘description’) |
aria-labelledby |
trigger | id of the tooltip, added to existing ids (relation ‘label’) |
The tooltip is never focusable and never moves focus. It shows on keyboard focus (:focus-visible) of the trigger, not on pointer focus.
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.3 Contrast (Minimum) | AA | |
| 1.4.11 Non-text Contrast | AA | |
| 1.4.13 Content on Hover or Focus | AA | |
| 2.1.1 Keyboard | A | |
| 4.1.2 Name, Role, Value | A |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- 1.4.13 dismissible: Escape hides it without moving pointer or focus.
- 1.4.13 hoverable: moving the pointer from the trigger onto the tooltip keeps it open (hideDelay grace period).
- 1.4.13 persistent: stays visible while the trigger is hovered or focused, until Escape or another tooltip opens.
- Only one tooltip is visible at a time.
- Touch pointers do not show tooltips; tooltips must never hold essential information.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.
Behavior
Section titled “Behavior”States
Section titled “States”hidden, pending (show delay running), visible, hiding (hide delay running).
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| hidden | mouse or pen enters the trigger | pending; visible after showDelay |
| pending | pointer leaves the trigger | hidden (never shown) |
| hidden | keyboard focus on the trigger (:focus-visible) |
visible immediately |
| visible | pointer leaves trigger and tooltip (not keyboard-focused) | hiding; hidden after hideDelay |
| hiding | pointer enters the trigger or the tooltip | visible |
| visible | trigger loses focus, Escape, pointer down elsewhere, another tooltip shows | hidden |
Accessibility notes
Section titled “Accessibility notes”- WCAG 1.4.13: dismissible (Escape), hoverable (the pointer can move onto the tooltip within
hideDelay), persistent (stays while hovered or focused). - Pointer focus (a click) does not show the tooltip; keyboard focus does.
- Touch pointers never show tooltips, so tooltips must never hold essential information.
relation: 'label'replaces the trigger’s accessible name; use it only for controls without visible text.- Manual screen-reader verification is pending (see Known limitations).
Responsive behavior
Section titled “Responsive behavior”Width up to min(tooltip-max-width, 100vw - 1rem); text wraps. The positioning engine flips and shifts to stay in the viewport.
Right-to-left
Section titled “Right-to-left”start and end placements are logical and mirror in RTL (direction option or global direction).
Theming
Section titled “Theming”Inverse surface (color-inverse with color-on-inverse text), verified in the light, dark, and high-contrast themes. In forced-colors mode the tooltip has a CanvasText border. The fade-in uses @starting-style and is removed under reduced motion or animation: 'none'.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { tooltip: { showDelay: 300, hideDelay: 200 } } });Changes apply to existing instances (a visible tooltip is repositioned).
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic.
Security
Section titled “Security”Content is set with textContent and never parsed as HTML. CSP-safe: positioning uses the CSSOM.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry.
Performance
Section titled “Performance”Five listeners on the trigger, two on the tooltip, and one configuration subscription per instance. While visible: one overlay-stack entry, one window pointerdown listener, and the positioning engine’s observers, all released on hide.
Supported data scale
Section titled “Supported data scale”Any number of instances per page; at most one is visible at a time.
Edge cases
Section titled “Edge cases”- Moving the pointer straight from the trigger onto the tooltip keeps it open, even with
hideDelay: 0(hiding is always asynchronous). - A tooltip shown by keyboard focus stays visible when the pointer leaves.
- Inside a Popover, the first Escape hides the tooltip and the second closes the popover.
- Pointer down outside the trigger and tooltip hides the tooltip before the overlay stack runs, so the overlay below still gets its outside-pointer dismissal.
- Inside a modal
<dialog>, the tooltip is appended to that dialog so it stays hoverable (the rest of the page is inert).
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
TOOLTIP_TRIGGER |
configuration | The trigger is not a connected HTMLElement. |
TOOLTIP_OPTIONS |
configuration | Empty or non-string content, or an invalid relation. |
CFG_* |
configuration | Invalid placement, showDelay, or hideDelay. |
A failed construction leaves no element, ARIA reference, listeners, or subscriptions behind. A failed update() keeps the previous options.
Known limitations
Section titled “Known limitations”- Touch pointers never show the tooltip.
- Disabled native buttons get no pointer or focus events; use
aria-disabledif they need a tooltip. - One visible tooltip per loaded copy of the module.
- The trigger gap is fixed at 6 px.
- Screen-reader behavior has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Unsupported scenarios
Section titled “Unsupported scenarios”- Rich or interactive content (use Popover).
- Showing on tap or long press.