# Tooltip A short label for a control, shown on hover and keyboard focus. ```ehtml Example import { Tooltip, TooltipProvider, TooltipTrigger } from "@elements/ui/tooltip"; import { Button } from "@elements/ui/button"; import { Icon } from "@elements/ui/icon"; ... ``` ## Parts | Part | What it is | |---|---| | `TooltipProvider` | Optional. Sets delay, skipDelay, closeDelay and disableHoverableContent for every tooltip inside it. | | `Tooltip` | The root: owns open, renders the trigger slot and, while open, the role=tooltip content. | | `TooltipTrigger` | Wraps a trigger anywhere on the page for the Tooltip with the same handle. Takes handle and payload. | ## Attributes ### Tooltip | Attribute | Type | Default | Description | |---|---|---|---| | `open` | `boolean` (two-way) | `false` | Whether the tooltip is open. Bind it to control it; it writes false back when it closes itself. | | `content` | `string` | `""` | The tooltip's text. For rich content, use the default slot. | | `label` | `string` | `""` | What a screen reader reads instead of the visible content (aria-label on the tooltip). | | `side` | `"top" \| "right" \| "bottom" \| "left" \| "inline-start" \| "inline-end"` | `"top"` | Preferred side; it flips when there is no room. inline-start and inline-end follow the text direction (right and left under dir=rtl). | | `align` | `"start" \| "center" \| "end"` | `"center"` | Alignment along that side. | | `sideOffset` | `number \| ((d: OffsetData) => number)` | `4` | Gap from the trigger, in px. | | `alignOffset` | `number \| ((d: OffsetData) => number)` | `0` | Shift along the alignment axis, in px. | | `avoidCollisions` | `boolean` | `true` | Flip and shift to stay on screen. | | `collisionAvoidance` | `{ side?: "flip" \| "shift" \| "none"; align?: "flip" \| "shift" \| "none"; fallbackAxisSide?: "start" \| "end" \| "none" } \| null` | `null` | How it stays in view. side "none" keeps the side with no flip, "shift" keeps the side and slides it over the trigger into view; align "flip" tries the other alignment before sliding, "shift" only slides, "none" neither; fallbackAxisSide "start" tries the inline start side of the other axis first, "end" (the default) the end side, "none" never moves it to the other axis. avoidCollisions={false} turns all of it off. | | `positionMethod` | `"fixed" \| "absolute"` | `"fixed"` | "absolute" places the tooltip in page coordinates instead of viewport ones. | | `collisionPadding` | `number` | `8` | Distance kept from the viewport edge, in px. | | `collisionBoundary` | `string \| Element \| Element[]` | `""` | A selector or elements whose edges flip and shift keep it inside, besides the viewport. | | `arrowPadding` | `number` | `6` | Distance the arrow keeps from the corners, in px. | | `sticky` | `"partial" \| "always"` | `"partial"` | "always" keeps it in the collision boundary after its anchor scrolls away. | | `hideWhenDetached` | `boolean` | `false` | Hide while the trigger is scrolled out of view. | | `anchor` | `string` | `""` | CSS selector of an element to position against instead of the trigger. | | `keepMounted` | `boolean` | `false` | Keep the closed tooltip in the page, hidden, rather than removing it. | | `disableAnchorTracking` | `boolean` | `false` | Place it once when it opens; it stays put while the page scrolls, and is placed again on a window resize. | | `handle` | `string` | `""` | Names it for TooltipTrigger parts elsewhere on the page. | | `triggerId` | `string` (two-way) | `""` | The id of the active trigger's element. Set it with open to open against that trigger. | | `payload` | `string` (two-way) | `""` | The payload of the TooltipTrigger it is showing for, for the content to read. | | `arrow` | `boolean` | `true` | Draw an arrow pointing at the trigger. | | `delay` | `number` | `-1` | ms the pointer rests before it opens. -1 uses the TooltipProvider's delay, else 700. | | `closeDelay` | `number` | `-1` | ms before it closes after the pointer leaves. -1 uses the TooltipProvider's closeDelay, else 0. | | `disableHoverableContent` | `boolean` | `false` | Close as soon as the pointer leaves the trigger, even toward the tooltip. | | `closeOnClick` | `boolean` | `true` | A press on the trigger closes it. | | `disabled` | `boolean` | `false` | Never open. | | `trackCursorAxis` | `"none" \| "x" \| "y" \| "both"` | `"none"` | Follow the pointer along this axis while it moves over the trigger. | | `class` | `string` | `""` | Extra classes on the tooltip. | | `onOpenChange` | `(open: boolean, details: OpenChangeDetails) => void` | `() => {}` | Called when the tooltip opens or closes itself, before the change. details.reason says why (trigger-press, trigger-hover, escape-key, outside-press, close-press, focus-out); details.trigger is the trigger element that caused it (undefined when no trigger did); details.cancel() keeps the current state. Not called for changes the caller makes. | | `onOpenChangeComplete` | `(open: boolean) => void` | `() => {}` | Called after the enter or exit animation finishes. | | `onEscapeKeyDown` | `(e: KeyboardEvent) => void` | `() => {}` | Called on Escape; e.preventDefault() keeps it open. | | `onPointerDownOutside` | `(e: PointerEvent) => void` | `() => {}` | Called on a press outside; e.preventDefault() keeps it open. | ### TooltipTrigger | Attribute | Type | Default | Description | |---|---|---|---| | `handle` | `string` | (required) | The handle it is a trigger for. | | `payload` | `string` | `""` | Data handed to payload while this trigger is active. | ### TooltipProvider | Attribute | Type | Default | Description | |---|---|---|---| | `delay` | `number` | `700` | Open delay for the tooltips inside. | | `skipDelay` | `number` | `300` | Within this many ms of a tooltip closing, the next opens at once. | | `closeDelay` | `number` | `0` | Close delay for the tooltips inside. | | `disableHoverableContent` | `boolean` | `false` | The same, for every tooltip inside. | ## Slots | Slot | Part | Content | |---|---|---| | `trigger` | | The described element. It gets data-state, and aria-describedby pointing at the tooltip while open. Wrap a disabled button in a focusable span. | | `default` | | Rich content, after the content attribute's text. | | `default` | `TooltipProvider` | The region whose tooltips share its settings. | ## Keyboard | Keys | Action | |---|---| | `Tab` | Focusing the trigger opens the tooltip at once; moving focus away closes it. | | `Space / Enter` | Closes the tooltip; the trigger's own action still runs. | | `Escape` | Closes the tooltip. Focus stays on the trigger. | ## Data attributes | Attribute | Values | On | Description | |---|---|---|---| | `data-trigger-disabled` | present | trigger | Set while disabled keeps the tooltip from opening. | | `data-state` | `"closed" \| "delayed-open" \| "instant-open"` | trigger, .tooltip | instant-open when it skipped the delay (another tooltip had just shown); it does not animate in. | | `data-side` | `"top" \| "right" \| "bottom" \| "left"` | .tooltip, .tooltip-arrow | The side it ended up on. | | `data-align` | `"start" \| "center" \| "end"` | .tooltip | | | `--transform-origin` | position | .tooltip | The anchor-facing edge; the enter animation scales from it. | | `--anchor-width, --anchor-height` | px | .tooltip | The trigger's size. | | `--available-width, --available-height` | px | .tooltip | Room to the viewport edge; caps the width. | | `--tooltip-arrow-size` | length | .tooltip | Set on the tooltip's class to size the arrow. | | `data-popup-open` | present | trigger | While open; the same moment as the trigger's open data-state. | | `data-overflowing` | present | .tooltip | Set while the content is taller than the room its side has; the tooltip scrolls and drops its arrow. | | `data-instant` | `"delay" \| "focus" \| "dismiss"` | .tooltip, .tooltip-arrow | delay when it skipped the delay, focus when keyboard focus opened it, dismiss when Escape or a press closed it. | | `data-open / data-closed` | present | .tooltip, .tooltip-arrow | The open state as two flags; data-closed during the exit animation. | | `data-align` | `"start" \| "center" \| "end"` | .tooltip-arrow | The alignment it ended up with. | | `data-uncentered` | present | .tooltip-arrow | When the arrow cannot point at the trigger's middle (held off a corner). | | `data-anchor-hidden` | present | .tooltip | With hideWhenDetached: while the trigger is scrolled out of view. | | `data-starting-style / data-ending-style` | present | .tooltip | On the first frame of the enter animation, and through the exit animation. | | `--positioner-width / --positioner-height` | px | .tooltip | The tooltip positions itself, so these are its own size while open. | ## Accessibility - The content has role="tooltip" and the trigger's aria-describedby includes its id while it is open, so a screen reader reads it after the control's name. - Keyboard focus opens it without delay; focus never moves into it, and it holds nothing focusable. - Escape closes it without moving focus. A press on the trigger closes it. - The pointer can move from the trigger onto the tooltip without it closing (WCAG 1.4.13, hoverable), unless disableHoverableContent is set. - Touch does not open it: put anything a touch user needs in the control's label. ## See also - [Button](button): A button or a link that looks like one, in six variants and four sizes. - [Icon](icon): An inline stroke icon from the set the templates draw their own controls with, sized in pixels and colored by the text around it. - [Popover](popover): Rich content in a floating panel, opened by a trigger, that keeps the page usable. - [HoverCard](hover-card): A preview of what a link points to, shown while the pointer rests on it.