Tooltip
Supplemental text disclosure for hover, focus, and long-press interactions.
Tooltip in motion
When to Use
Use Tooltip for a short text hint that explains a control without requiring
interaction, especially an unfamiliar icon. Use visible text when the
information is important, HoverCard for a richer preview, and Popover when
the floating content contains buttons, links, or other controls.
Features
The behavior Atom owns before your product adds appearance.
- Provider-level delay configuration.
- Controlled and uncontrolled open state.
- Opens on pointer hover, keyboard focus-visible, and a stationary 700 ms touch long press.
- Cancels touch opening on early release, movement beyond 10 CSS pixels,
scrolling, a second touch,
touchcancel, disabling, or Trigger unmount. - Starts finite touch dismissal after release: 1500 ms for plain and 3000 ms for rich.
- Floating UI positioning that preserves centered alignment by shifting within the viewport first. Edge-aligned content resolves alternate alignments before shifting, and both modes retain opposite- and perpendicular-side fallbacks; Arrow coordinates follow the resolved result.
aria-describedbywiring between trigger and tooltip content.- Portal and arrow parts.
Import
Anatomy
API Reference
Provider
Shares open, close, and skip-delay timing between descendant tooltips. Provider renders no DOM element.
| Prop | Type | Default |
|---|---|---|
children | ReactNode | required |
openDelay | number | 400 |
closeDelay | number | 150 |
skipDelay | number | 300 |
ARIA: Provider renders no element and adds no ARIA attributes.
Data attributes: Provider renders no element and exposes none.
Root
Owns one tooltip's open state, timers, Escape dismissal, touch state, and plain or rich hover behavior. Root renders no DOM element.
| Prop | Type | Default |
|---|---|---|
children | ReactNode | required |
open | boolean | - |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | - |
openDelay | number | Provider value or 400 |
closeDelay | number | Provider value or 150 |
disabled | boolean | false |
variant | "plain" | "rich" | "plain" |
ARIA: Root renders no element and adds no ARIA attributes.
Data attributes: Root renders no element and exposes none.
Trigger
Reference element that describes itself with tooltip content while open.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
render | RenderProp | - |
| ARIA attribute | Values |
|---|---|
aria-describedby | Content ID while the tooltip is open |
| Data attribute | Values |
|---|---|
[data-slot] | "tooltip-trigger" |
Portal
Moves Content to another DOM container without rendering a wrapper.
| Prop | Type | Default |
|---|---|---|
container | HTMLElement | null | document.body after mount |
disabled | boolean | false |
ARIA: Portal adds no ARIA attributes.
Data attributes: Portal renders no wrapper and exposes none.
Content
Renders the positioned tooltip text and keeps Content available while the
pointer moves from Trigger into Content.
Content exposes measured --atom-floating-available-width and
--atom-floating-available-height properties.
Portalled Content preserves an explicit dir; otherwise it resolves direction
from Trigger and then Direction.Provider.
| Prop | Type | Default |
|---|---|---|
side | "top" | "right" | "bottom" | "left" | "top" |
align | "start" | "center" | "end" | "center" |
sideOffset | number | 4 |
ariaLabel | string | - |
onMouseEnter | MouseEventHandler<HTMLDivElement> | - |
onMouseLeave | MouseEventHandler<HTMLDivElement> | - |
| ARIA attribute | Values |
|---|---|
role | "tooltip" |
aria-label | Value from ariaLabel when provided |
| Data attribute | Values |
|---|---|
[data-slot] | "tooltip" |
[data-state] | "open" | "closed" |
[data-side] | "top" | "right" | "bottom" | "left" |
[data-variant] | "plain" | "rich" |
[data-positioned] | Present after the first positioning frame |
Plain Content is normally one short description. Rich Content may use a short
title, supporting description, and non-interactive inline formatting. Both
variants retain role="tooltip"; neither may contain links, buttons, inputs,
or other focusable controls. Use HoverCard for a larger non-interactive
preview and Popover for an interactive surface.
Arrow
Renders a decorative SVG pointer using the final side chosen after collision
handling. getTooltipArrowGeometry exposes the same geometry for custom arrows.
| Prop | Type | Default |
|---|---|---|
width | number | 10 |
height | number | 5 |
asChild | boolean | false |
render | RenderProp | - |
ARIA: Arrow is decorative and hidden from assistive technology.
| Data attribute | Values |
|---|---|
[data-slot] | "tooltip-arrow" |
[data-side] | "top" | "right" | "bottom" | "left" |
Advanced compound parts can read the Provider, Root, and Content contexts with
their public hooks and providers. getTooltipArrowGeometry returns the same SVG
geometry used by Arrow.
Examples
Basic Tooltip
Custom Trigger
Rich, Non-Interactive Tooltip
Accessibility
Tooltip follows the WAI-ARIA tooltip pattern.
Content is referenced by aria-describedby while open and must remain
non-interactive in both plain and rich variants. The Trigger needs a complete
accessible name independently; Tooltip provides only a supplemental
description.
| Key | Description |
|---|---|
Tab | Moving focus to a focus-visible trigger can open the tooltip. |
Shift+Tab | Moving focus away closes the tooltip. |
Escape | Closes the topmost open tooltip immediately. |
On touch devices, a stationary 700 ms press opens Tooltip immediately without
adding the hover openDelay. Touch-generated compatibility hover/focus events
do not open Tooltip after a quick tap. Ordinary taps and scrolling are not
suppressed; native text selection and the context callout are suppressed only
while the Trigger is tracking the competing stationary long-press gesture.
An opened Tooltip remains visible while the initiating finger is down. After
release, plain dismisses after 1500 ms and rich after 3000 ms; an outside touch
or scroll dismisses either immediately. Moving more than 10 CSS pixels,
scrolling, adding a second touch, receiving touchcancel, disabling the
Trigger, or unmounting it cancels the touch session.
Changelog
Unreleased
0.24.0
- Added public Agent Knowledge for component selection, required composition, recurring mistakes, and validation.
- Preserved centered Content alignment near viewport edges by shifting it into view before considering alternate placements.
0.6.9
- Preserved resolved Trigger or provider direction on portalled Content while
retaining explicit Content
dirprecedence.
0.6.8
- Exposed measured available dimensions through headless floating properties for constrained styled surfaces.
0.6.3
- Prioritized every usable alignment on the requested side, followed by the opposite side, before allowing perpendicular-axis collision fallbacks.
0.6.2
- Added perpendicular-side collision fallbacks after the preferred and opposite sides so constrained tooltips can resolve onto the axis with available room.
0.6.1
- Added immediate outside-touch and scroll dismissal after a long-press Tooltip has opened and the initiating finger is released.
0.3.5
- Corrected touch long press to open once at the 700 ms threshold without also paying the hover delay.
- Added complete touch-session cancellation for early release, movement beyond
10 CSS pixels, scrolling, a second touch,
touchcancel, disabled changes, and Trigger unmount. - Ignored touch-generated compatibility hover/focus events after release so a quick tap cannot enter the desktop opening path, and suppressed native text selection/callout only while a long press is actively being tracked.
- Moved touch auto-dismissal to release time, retaining 1500 ms for plain and adding a finite 3000 ms rich dismissal.
- Clarified that plain and rich Content are both non-interactive and that actionable floating content belongs in Popover.
0.3.1
- Fixed exit-presence cleanup so closed Tooltip Content unmounts after its CSS motion window even when no end event is emitted.
0.2.0
- Fixed Tooltip render trigger positioning by updating Floating UI after the trigger ref commits.
- Added
data-variant="plain|rich"to Tooltip content and documented thevariantRoot prop. - Added shared dismissable layer Escape handling so Tooltip participates in topmost-layer dismissal with other overlays.
0.1.0
- Initial Atom release.