Tooltip
Tooltip shows a short description of a control. It opens when the pointer rests on the control, or when the keyboard puts the focus on it. It holds text and nothing else: no link, no button, no field. A screen reader reads the text after the name of the control.
Anatomy
Tooltip.Root holds the open state and the delays. Tooltip.Trigger is the button that the tooltip describes. Tooltip.Content is the panel, in a portal, positioned against the trigger. Tooltip.Arrow in the content points at the trigger.
Tooltip.Provider around a group of tooltips gives them the same delays.
<script>
import { Tooltip } from '@human-kit/ui';
</script>
<Tooltip.Root>
<Tooltip.Trigger aria-label="Bold">B</Tooltip.Trigger>
<Tooltip.Content>
Bold
<Tooltip.Arrow />
</Tooltip.Content>
</Tooltip.Root>When to use it
A tooltip is for a description the user can do without. Examples: the name of an icon button, a keyboard shortcut, the full text of a cut label. It is not for a message the user must read. A touch screen has no hover, and a screen reader reads it only as a description. Put an important message in the page, or in a Popover.
The trigger must have a name of its own, in its text or in aria-label. The tooltip is the description, not the name.
Open and close
The tooltip opens when the pointer rests on the trigger for delay milliseconds. A keyboard focus opens it at once. A focus that a script gives does not open it, and a tap does not open it: a finger lands and presses. A long press of a finger opens it.
It closes when the pointer leaves the trigger and the content, when the focus leaves, on Escape, and on a press on the trigger. A press does something, and the tooltip gets out of the way.
The pointer can move from the trigger to the content. While it moves in a straight line toward the content, the tooltip waits for it. A move to the side closes it, and so does a stop of 300 milliseconds in the gap. closeDelay adds a wait before each close. The content then keeps the tooltip open while the pointer rests on it. Thus the user can read a long text to the end, and select it.
Touch
A touch has no hover, thus a tap does not open a tooltip: it presses the control. A long press of a finger or a pen opens it. The tooltip then stays open until a press somewhere else, a tap on the trigger, or Escape. The click and the contextmenu of that long press do not reach the control. A trigger that is not a button, with text in it, needs user-select: none: without it, the long press selects the text.
Set openOnLongPress={false} on the root for a control where a long press has a meaning of its own, for example a text selection. That tooltip then does not open on a touch: give the control a visible name when a touch user needs it.
A group of tooltips
One tooltip at most is open. When a second one opens, the first one closes.
The first tooltip of a row waits delay; the next ones open at once while the user moves along the row. That window after a close is skipDelay. Put a Tooltip.Provider around a toolbar to give the same delays to each tooltip in it.
A wide trigger
For a trigger much wider than the tooltip, for example a progress bar, set followPointer on the content. The panel then moves with the pointer along that axis, and it stays against the trigger on the other axis. A tooltip that a keyboard focus opened stays at the center of the trigger.
Any trigger
Tooltip.Trigger renders a button. For another element, give the element to triggerRef on the root. The root then listens to that element, and it writes aria-describedby and data-state on it.
Styles
Tooltip.Content is position: fixed in a portal, above the topmost dialog. It shows data-state, data-placement, data-entering and data-exiting. Animate the enter and the exit with a CSS transition on data-entering and data-exiting: the panel stays in the DOM until the exit transition ends.
Tooltip.Arrow is position: absolute. The panel moves it along the edge that faces the trigger, and it writes the side in data-placement. Give the arrow a size and a shape, and put it at the edge with CSS. For data-placement="top" the arrow sits at the bottom edge of the panel.
Keyboard
Tabto the trigger opens the tooltip.Tabaway closes it.Escapecloses it. ThatEscapecloses nothing else.
Accessibility
Tooltip.Contenthasrole="tooltip", and the trigger points at it witharia-describedbywhile the content is in the DOM. A screen reader reads the description after the name of the trigger.- The tooltip takes no focus, and a screen reader does not enter it. Put only text in it.
- A keyboard focus opens it at once, without the delay of the pointer. A focus that a script gives, for example after a menu closes, opens it only when the user got there with the keyboard.
- The content stays open while the pointer rests on it, and
Escapecloses it without a move of the pointer. - A long press opens the tooltip on a touch, and a tap presses the control. A tooltip with
openOnLongPress={false}does not open on a touch: give that control a visible name when a touch user needs it.
API reference
Root
The open state, the delays and the interaction with the trigger. It renders no element.
* required. Native HTML attributes of the underlying element are also accepted.
Provider
The delays of every tooltip inside it. It renders no element.
* required. Native HTML attributes of the underlying element are also accepted.
Trigger
The button that the tooltip describes. It renders a native button, and it points at the content with aria-describedby while the content is in the DOM.
* required. Native HTML attributes of the underlying element are also accepted.
Content
The floating panel with the description. It renders a div with role="tooltip" in a portal, positioned against the trigger.
* required. Native HTML attributes of the underlying element are also accepted.
Arrow
The pointer of the panel toward the trigger. It renders a span, moved along the edge that faces the trigger.
* required. Native HTML attributes of the underlying element are also accepted.