Tooltip
Brief contextual hint anchored to a focusable trigger, built on Radix primitives.
<TooltipProvider> <Tooltip> <TooltipTrigger asChild> <IconButton aria-label="Add to library"> <Plus /> </IconButton> </TooltipTrigger> <TooltipContent>Add to library</TooltipContent> </Tooltip></TooltipProvider>Usage
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@reva/ui";Tooltips are sighted-user enhancements — pair the trigger with a focusable element (Button, IconButton, link) so keyboard and assistive-technology users still reach the underlying action without depending on the tooltip text. Wrap your app once with TooltipProvider (typically at the root layout) so all descendant tooltips share a delayDuration.
Composition
Use the following composition to build a Tooltip:
TooltipProvider
└── Tooltip
├── TooltipTrigger
└── TooltipContentTooltipProvider lives once near the app root and accepts delayDuration and skipDelayDuration for all descendants. Individual Tooltip instances may override delayDuration per-trigger.
Examples
Basic
<TooltipProvider> <Tooltip> <TooltipTrigger asChild> <Button variant="outline">Hover me</Button> </TooltipTrigger> <TooltipContent>Brief contextual hint</TooltipContent> </Tooltip></TooltipProvider>Sides
Use the side prop on TooltipContent to position the tooltip on the top, right, bottom, or left of the trigger. Radix flips automatically on viewport collisions.
<TooltipProvider> <HStack gap={4}> <Tooltip> <TooltipTrigger asChild> <Button variant="outline">Top</Button> </TooltipTrigger> <TooltipContent side="top">On top</TooltipContent> </Tooltip> <Tooltip> <TooltipTrigger asChild> <Button variant="outline">Right</Button> </TooltipTrigger> <TooltipContent side="right">On right</TooltipContent> </Tooltip> <Tooltip> <TooltipTrigger asChild> <Button variant="outline">Bottom</Button> </TooltipTrigger> <TooltipContent side="bottom">On bottom</TooltipContent> </Tooltip> <Tooltip> <TooltipTrigger asChild> <Button variant="outline">Left</Button> </TooltipTrigger> <TooltipContent side="left">On left</TooltipContent> </Tooltip> </HStack></TooltipProvider>With keyboard shortcut
Place Kbd glyphs inside TooltipContent to surface the keyboard shortcut alongside the action label. Kbd automatically inverts its colours when nested inside a tooltip.
<TooltipProvider> <HStack gap={2}> <Tooltip> <TooltipTrigger asChild> <Button variant="outline">Save</Button> </TooltipTrigger> <TooltipContent> Save <KbdGroup> <Kbd>⌘</Kbd> <Kbd>S</Kbd> </KbdGroup> </TooltipContent> </Tooltip> <Tooltip> <TooltipTrigger asChild> <Button variant="outline">New file</Button> </TooltipTrigger> <TooltipContent> New file <KbdGroup> <Kbd>⌘</Kbd> <Kbd>N</Kbd> </KbdGroup> </TooltipContent> </Tooltip> </HStack></TooltipProvider>On disabled trigger
Disabled buttons don't fire pointer events, so wrap them in a focusable <span tabIndex={0}> to give the tooltip something to anchor to. Add pointer-events-none to the inner button so the span receives the events.
<TooltipProvider> <Tooltip> <TooltipTrigger asChild> <span tabIndex={0}> <Button variant="outline" disabled className="pointer-events-none"> Submit </Button> </span> </TooltipTrigger> <TooltipContent>Complete required fields first</TooltipContent> </Tooltip></TooltipProvider>With custom delay
Set delayDuration on TooltipProvider to tune how quickly tooltips open. The default is 0 (snappy); pass a higher number for the classic patient-tooltip feel.
<TooltipProvider delayDuration={500}> <Tooltip> <TooltipTrigger asChild> <Button variant="outline">Hover (500ms delay)</Button> </TooltipTrigger> <TooltipContent>Took 500ms to appear</TooltipContent> </Tooltip></TooltipProvider>Props
| Component | Prop | Type | Default | Description |
|---|---|---|---|---|
| TooltipProvider | delayDuration | number | 0 | Milliseconds before a tooltip opens on hover or focus. |
| TooltipProvider | skipDelayDuration | number | 300 | Window during which the next tooltip skips its open delay. |
| TooltipProvider | disableHoverableContent | boolean | false | Prevent the pointer from entering the content surface. |
| Tooltip | defaultOpen | boolean | — | Uncontrolled initial open state. |
| Tooltip | open | boolean | — | Controlled open state. |
| Tooltip | onOpenChange | (open: boolean) => void | — | Called when open state changes. |
| Tooltip | delayDuration | number | inherits Provider | Per-instance override. |
| TooltipTrigger | asChild | boolean | false | Merge props onto the child element instead of rendering a <button>. |
| TooltipContent | side | "top" | "right" | "bottom" | "left" | "top" | Preferred side; Radix may flip on viewport collision. |
| TooltipContent | sideOffset | number | 0 | Distance in pixels from the anchor. |
| TooltipContent | align | "start" | "center" | "end" | "center" | Alignment along the chosen side. |
| TooltipContent | alignOffset | number | 0 | Pixel offset from start or end alignment. |
| TooltipContent | avoidCollisions | boolean | true | Auto-flip when content would clip the viewport. |
| TooltipContent | className | string | — | Merged onto the content surface. |
Radix passthrough props on each part are supported; see the Tooltip primitives overview.