Tooltip
Small floating label triggered by hover (web) or long-press (native). For short contextual hints — most often on icon-only buttons.
At a glance
- Compose:
Tooltip,TooltipTrigger,TooltipContent. Trigger usesasChildby default — wrap any element (Button, Link, custom Pressable) and it becomes the activator. - Cross-platform: web opens on hover or focus; native opens on long-press (500ms hold).
- Configurable open / close delays via
delayMs(default 500ms) andcloseDelayMs(default 0ms). - Accessibility: trigger gets
aria-describedbypointing at the content's id (the tooltip augments the trigger's accessible name — it does not replace it). Content getsrole="tooltip"with a unique id.
Tooltip vs Popover
- Tooltip — small hover/long-press hint with non-interactive text. Use for short labels like "Click to view details" on icon-only buttons. Augments the trigger's accessible name; not a focus stop.
- Popover — anchored, non-modal, can hold interactive content (forms, buttons, color pickers). Dismisses on outside click + Escape. Use Popover when the surface needs to be clicked into.
Preview
Sides
TooltipContent accepts a side of 'top', 'right', 'bottom', or 'left' (default 'top'). Pair it with align ('start' | 'center' | 'end', default 'center') to fine-tune placement along the chosen edge.
Anatomy
| Subcomponent | Role |
|---|---|
Tooltip | Root — owns open state and the open / close timers. |
TooltipTrigger | Element that reveals the tooltip. asChild by default. |
TooltipContent | The floating label. Renders only while open. |
Delays
Open state — open, defaultOpen, onOpenChange
Pass open for controlled mode and pair with onOpenChange. Pass
defaultOpen for uncontrolled mode when you want the tooltip
pre-opened on first render (rare, useful during onboarding tours).
Mixing the two prefers controlled and ignores defaultOpen.
Accessibility
The trigger receives aria-describedby referencing the content's id only while the tooltip is open. This means the tooltip text is announced in addition to the trigger's existing accessible name — so an icon-only button still needs its own aria-label:
The content has role="tooltip" and is non-interactive (pointerEvents: 'none') — if you need a panel users can click into, reach for Popover instead. Pressing Escape while the tooltip is open dismisses it.
Native behavior
On iOS and Android there is no hover, so the tooltip opens on a 500ms long-press of the trigger and dismisses on the next tap anywhere. The chip is rendered with absolute positioning relative to where it sits in the tree — the parent needs to allow overflow for the chip to peek out. For richer native overlays, prefer Popover.
Props
Tooltip
| Prop | Type | Default | Description |
|---|---|---|---|
closeDelayMs | number | 0 | Delay before the tooltip closes after hover-out / blur. Useful for giving users time to move into the tooltip if it ever becomes interactive (it shouldn't — use Popover for that — but the knob is here so the API matches Radix). @defaultValue 0 |
defaultOpen | boolean | false | Uncontrolled initial open state. @defaultValue false |
delayMs | number | 500 | Delay before the tooltip opens after hover/focus. @defaultValue 500 |
onOpenChange | (open: boolean) => void | — | Fires with the new open state. |
open | boolean | — | Controlled open state. |
TooltipTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | true | Render the child as the trigger (Slot pattern). Default true — pass `false` for an inline pressable. |
className | string | — | — |
testID | string | — | — |
TooltipContent
| Prop | Type | Default | Description |
|---|---|---|---|
align | enum | center | Alignment along the trigger edge. @defaultValue 'center' |
className | string | — | — |
side | enum | top | Side of the trigger to anchor on. @defaultValue 'top' |
testID | string | — | — |