Skip to content

ComponentsOverlays

Tooltip

A short label shown on hover or keyboard focus, for icon-only buttons, abbreviations and extra context. Tuned delays, a shared warm-up between tooltips, dark and light variants, and an arrow that follows the placement.

React AriaSource

Installation

pnpm dlx shadcn@latest add @desyne/tooltip

The CLI installs dependencies and any other components this one uses.

Usage

tsx
import { Tooltip, TooltipTrigger } from "@/components/ui/tooltip";
tsx
<TooltipTrigger>
  <Button variant="ghost" size="icon" aria-label="Save">
    <SaveIcon />
  </Button>
  <Tooltip>Save</Tooltip>
</TooltipTrigger>

TooltipTrigger wraps a focusable trigger (a Button, Link, ToggleButton or any element inside React Aria's Focusable) and the Tooltip that describes it.

Tooltips supplement, they don't replace labels

The tooltip is linked to its trigger with aria-describedby, so it's read as a description after the trigger's name. Icon-only buttons still need an aria-label. Touch users never see tooltips, so don't put essential information or interactive content in them; use a Popover instead.

When to use

  • Tooltip — a brief label or hint for a control, especially icon-only buttons, abbreviations and truncated text.
  • Popover — interactive content, or anything users need to read on touch devices.
  • Inline help text (a field description) — guidance that should always be visible.
  • Toast — feedback about something that just happened.

Anatomy

tsx
<TooltipTrigger>          {/* hover, focus and delay handling */}
  <Button />              {/* focusable trigger */}
  <Tooltip>               {/* role="tooltip", optional arrow */}
    Label
  </Tooltip>
</TooltipTrigger>
PartRendersNotes
TooltipTrigger—Opens the tooltip on hover (after delay) or keyboard focus (immediately). Defaults to a 400ms open and 100ms close delay.
Tooltip<div role="tooltip"> (portal)The positioned bubble. Carries data-slot="tooltip".
ArrowOverlayArrow › <svg>8px arrow pointing at the trigger. Rendered unless showArrow={false}.

Examples

Placement

placement accepts top (default), bottom, left, right, start, end and combinations like top start. The tooltip flips to the opposite side when there isn't room, and the arrow rotates with it.

Light variant

variant="light" renders a bordered card that matches popovers. Use it for two-line content, like a metric name and its definition. Tooltips are capped at max-w-xs; pass a max-w-* class for a narrower measure.

Without arrow

showArrow={false} hides the arrow. Drop the offset to keep the tooltip close to dense toolbars.

With keyboard shortcut

Tooltips are a natural place to advertise shortcuts. Put a Kbd in the content; the light variant keeps it legible.

Delay

delay and closeDelay on TooltipTrigger set how long hover waits before opening and closing. Once one tooltip has opened, moving to a nearby trigger opens the next one immediately. Keyboard focus always opens without delay.

Focus only

trigger="focus" shows the tooltip for keyboard focus only, not on hover. Use it for hints that would be noisy under the mouse.

Controlled

isOpen and onOpenChange on TooltipTrigger let you open the tooltip from code, like confirming a copy action. shouldCloseOnPress={false} keeps it open while the trigger is pressed.

npm i @acme/sdk

Disabling tooltips

isDisabled on TooltipTrigger turns the tooltip off without touching the trigger. Here tooltips only appear while the navigation is collapsed to icons. Disabled buttons never show tooltips, since they don't receive hover or focus.

Custom trigger

Wrap non-interactive elements in React Aria's Focusable so they can own a tooltip. The child needs tabIndex={0} and an ARIA role (button, img, link and similar), and must forward its ref.

Median latency (p50) dropped to 182 ms this week −12%

Recipes

Collapsed navigation

An icon rail with right-side tooltips that show each destination and its shortcut. delay={0} makes scanning the rail instant.

Avatar stack

Overlapping Avatars, each wrapped in Focusable with role="img" and a name, show who has access on hover or focus.

  • AO
  • BC
  • CM
  • DP
4 collaborators

Metric definitions

KPI cards with an info button next to each label. The light variant holds the metric's name and a short definition.

Net revenue retention

118%

+4.2 pts vs last quarter

Payback period

11.4 mo

−0.8 mo vs last quarter

Accessibility

  • The tooltip has role="tooltip" and is linked to its trigger with aria-describedby, so screen readers read it after the trigger's name.
  • It opens on hover after delay, and immediately when the trigger receives keyboard focus. It doesn't open for touch.
  • It closes on Esc, when the pointer leaves (after closeDelay), when focus moves away, and when the trigger is pressed (unless shouldCloseOnPress={false}).
  • Keep tooltip content short and non-interactive. Anything focusable inside a tooltip can't be reached.
  • The trigger must be focusable. Wrap plain elements in Focusable with a tabIndex and a role.

Keyboard

KeyAction
TabFocusing the trigger opens the tooltip
EscHides the tooltip

Styling

Data attributes

On the Tooltip:

AttributePresent when
data-placementAlways: the resolved side, "top", "bottom", "left" or "right"
data-enteringOpening animation is running
data-exitingClosing animation is running
data-slot="tooltip"Always

The enter animation fades, zooms and slides in from the trigger's side based on data-placement.

Customizing

  • className on Tooltip styles the bubble: it's w-fit max-w-xs rounded-md px-2.5 py-1.5 text-xs with text-balance. Pass max-w-* or padding classes to change it, or flex items-center gap-2 to lay out rich content.
  • The default variant uses bg-foreground text-background, so it inverts with the theme; light uses bg-popover with a border.
  • The arrow's fill follows the variant. When overriding the background, hide the arrow or restyle it via [&_svg]:fill-….
  • --trigger-anchor-point is set on the tooltip, for a custom transform-origin.

Render props

className and children accept a function of the tooltip's state:

tsx
<Tooltip className={({ placement }) => (placement === "bottom" ? "mt-1" : "")}>
  Label
</Tooltip>

API Reference

TooltipTrigger

Prop

Type

Also accepts every prop of React Aria's TooltipTrigger.

Tooltip

Prop

Type

Also accepts every prop of React Aria's Tooltip.

  • Popover — interactive content anchored to a trigger.
  • Button — icon-only buttons are the most common tooltip trigger.
  • Kbd — show shortcuts inside tooltips.
  • Toggle Button — label icon-only toggles with a tooltip.