Tooltip
A positioned descriptive surface shown on hover or focus. The trigger keeps focus and the tooltip is exposed via aria-describedby.
Features
- Hover and focus open
- Delayed close with hover bridge
- Escape to dismiss
- Portalled tooltip content
- Placement-aware state hooks
- Optional arrow
Installation
npm install @ariaui/tooltip
Examples
Two playgrounds from the legacy doc: uncontrolled hover/focus and controlled open state. Shared layout classes live in tooltipExampleTokens.ts next to these demos.
Content uses role="tooltip" and stays non-interactive — use Popover or HoverCard when users need to act inside the panel.
Uncontrolled
Default open-on-hover/focus behavior with placement and offset; no React state required.
No preview output yet.
Controlled
Drive visibility with open and onOpenChange, useful when coordinating with other UI or analytics.
No preview output yet.
Framer Motion
Keep the tooltip mounted through close and let Framer Motion animate the surface.
No preview output yet.
Anatomy
import * as Tooltip from "@ariaui/tooltip";
export default function Example() {
return (
<Tooltip.Root>
<Tooltip.Trigger />
<Tooltip.Content />
</Tooltip.Root>
);
}
API Reference
Root
Context provider and state owner for the tooltip. Does not render a DOM element.
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | — |
placement | string | 'top' |
offset | number | — |
Trigger
Element that opens and closes the tooltip. Renders a `<button>` by default; use `asChild` to slot trigger props onto another element. Hover and focus open the tooltip. Mouse leave and blur close it, while moving the cursor from the trigger to the tooltip content keeps it open.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
hover | boolean | true |
focus | boolean | true |
| Attribute | Values |
|---|---|
| aria-describedby | ID of the `Content` element when open; absent when closed |
Content
Portalled tooltip panel. Renders nothing when closed. Hovering over the content cancels the close timer; leaving restarts it. Renders a `<div>`.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
arrow | boolean | false |
| Attribute | Values |
|---|---|
| role | 'tooltip' |
| data-state | 'delayed-open' when visible |
| data-side | active placement side — 'top', 'bottom', 'left', or 'right' |
Keyboard
| Shortcut | Action |
|---|---|
| Esc | Immediately closes the tooltip when the trigger has focus. |
| Tab | Moves focus away from the trigger, closing the tooltip. |
| Shift+Tab | Moves focus away from the trigger, closing the tooltip. |
Accessibility
Tooltip follows the WAI-ARIA APG Tooltip pattern — a descriptive surface that supplements, but never replaces, the trigger's accessible name:
- The
Contentelement receivesrole="tooltip"and an auto-generatedidthat theTriggerexposes viaaria-describedbywhile open. Focus stays on the trigger — tooltip content is never a focus target. - The trigger must be keyboard-focusable. Use a native
<button>(the default) or passaswith an interactive element; wrapping a non-focusable element requirestabIndex={0}so keyboard users can reveal the tooltip. Escapecloses an open tooltip immediately without moving focus, so keyboard users can dismiss a tooltip that overlaps other content.- Never put essential information only in a tooltip. Touch-only users and some assistive-tech users cannot hover — duplicate critical content in a visible label, description, or help text.
- Keep tooltip content short and non-interactive. Interactive controls inside a tooltip violate the pattern; use a
PopoverorHoverCardwhen users must click or tab into the content. data-sidereflects the active placement so you can style the arrow and transitions per-edge without additional JS.