v0.5

Tooltip

Short hover hint that names a control or explains a brief detail.

Description

Tooltip is a compound primitive built on Radix Tooltip. It composes Tooltip, TooltipTrigger, and TooltipContent into a hover-and-focus popover that surfaces a short label next to a control. The bundled Tooltip self-provides a Radix Tooltip.Provider, so you can drop a single instance anywhere without wiring extra context.

Reach for it when the trigger is an icon-only button, a truncated label, or any control whose purpose isn't fully obvious from its visual. Toolbars, table row actions, and avatar stacks are the natural homes. Content stays short: a verb phrase, a name, a date stamp, a keyboard shortcut.

Don't use it for rich content. If the message has focusable elements (links, buttons, inputs), use Popover. If you want a small info icon paired with a hint, use InfoTooltip. For status messages that follow an action, use Toast. For a persistent inline note that belongs in the page flow, use InlineAlert.

Installation

pnpm dlx @create-ui/cli add tooltip

Anatomy

Tooltip ships its own Radix Tooltip.Provider, so the three parts below are the entire public composition. TooltipProvider is exported for advanced cases where you want to set defaults on a region that holds raw Tooltip.Root instances.

<Tooltip>
  <TooltipTrigger />
  <TooltipContent />
</Tooltip>

Usage

import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip"
<Tooltip>
  <TooltipTrigger asChild>
    <Button>Save</Button>
  </TooltipTrigger>
  <TooltipContent>Save changes</TooltipContent>
</Tooltip>

Examples

Variants

variant on TooltipContent picks the color. primary is the default brand fill. neutral reads as a dark chip on light surfaces. inverse is a light chip with a soft shadow for use on dark or photo surfaces. danger and info carry status intent (destructive hints and helper text).

Sides

side chooses placement relative to the trigger (top, right, bottom, left). Radix flips the side automatically when the chosen direction would clip against the viewport edge.

With and Without Arrow

showArrow toggles the SVG caret. When the arrow is on, sideOffset defaults to 2.5 so the caret tucks into the trigger. When it's off, the offset adds 5 extra pixels so the floating chip still keeps a visible gap.

Long Content

TooltipContent caps at max-w-[200px] and wraps. Use it for two or three lines of context, no more. For anything paragraph-length, switch to Popover.

Delay

Pass delayDuration (milliseconds) on Tooltip to control how long the user must hover before the content opens. 0 opens instantly. 300 to 500 feels natural for dense toolbars; longer delays suit content that should reveal only on deliberate hover.

Accessibility

The trigger must be a focusable element. With asChild (the common case), TooltipTrigger forwards its props onto the wrapped element, so a <Button> keeps its native focus and key behavior.

KeyDescription
TabMoves focus to the trigger; opens the tooltip.
EscCloses the open tooltip.
SpaceDoes not toggle the tooltip; activates the trigger.
EnterDoes not toggle the tooltip; activates the trigger.

ARIA notes:

  • Radix sets role="tooltip" on the content and wires aria-describedby from the trigger to the content while it's open.
  • Tooltips are informational, not activating. Never put a primary action inside a tooltip; the content disappears on blur and is inaccessible to touch users without a hover state.
  • The trigger must have a visible focus indicator and an accessible name on its own (text or aria-label). Tooltips augment a name, they don't replace it.
  • For deeper portal, collision, and animation behavior, see Radix Tooltip.

Styling

Tailwind override: pass className to merge classes on the content (or the trigger). Classes are merged with the component's CVA classes via cn():

<TooltipContent className="font-mono">⌘K</TooltipContent>

Data slots and attributes: the component sets these for CSS targeting:

  • data-slot="tooltip-provider" on the optional shared provider.
  • data-slot="tooltip" on the root.
  • data-slot="tooltip-trigger" on the trigger.
  • data-slot="tooltip-content" on the portalled content surface.
  • data-slot="tooltip-arrow" on the arrow wrapper when showArrow is set.
  • Radix-managed: data-state="delayed-open" | "instant-open" | "closed" and data-side="top" | "right" | "bottom" | "left" on the content.

Target a state in CSS:

[data-slot="tooltip-content"][data-side="top"] {
  /* ... */
}
  • InfoTooltip: icon-with-hint pattern; use when the trigger is purely a help icon next to a label.
  • Popover: click-activated overlay with focusable content; use for anything richer than a single hint.
  • Toast: time-bounded message after an action; use for confirmations and errors.
  • InlineAlert: persistent in-flow callout; use when the message should stay visible without hover.

API Reference

Tooltip

Wraps Radix's Tooltip.Root and ships its own Tooltip.Provider, so a single Tooltip works without any ancestor setup. Extends React.ComponentProps<typeof TooltipPrimitive.Root>, so all Radix root props pass through.

Props

PropTypeDefaultDescription
defaultOpenboolean-Uncontrolled initial open state. Useful for static previews.
openboolean-Controlled open state.
onOpenChange(open: boolean) => void-Fires when the tooltip opens or closes.
delayDurationnumber0Milliseconds to wait on hover before the content appears.
disableHoverableContentboolean-Prevent the content from staying open when the pointer moves over it.
childrenReact.ReactNode-A TooltipTrigger and a TooltipContent.

TooltipTrigger

Wraps Radix's Tooltip.Trigger. Applies inline-flex so the trigger lays out consistently when used asChild. Extends Radix Tooltip.Trigger props (asChild, aria-label, etc.).

Props

PropTypeDefaultDescription
asChildbooleanfalseRender the child as the trigger via Radix Slot. Use it to wrap a Button or a link.
classNamestring-Tailwind classes merged with the component's classes via cn().
childrenReact.ReactNode-The trigger element (or the Button / link when using asChild).

TooltipContent

Wraps Radix's Tooltip.Content inside a Tooltip.Portal. Provides the chip surface, optional arrow, and the variant color set. Extends React.ComponentProps<typeof TooltipPrimitive.Content> minus the props that are managed internally (side, align, sideOffset, className, children).

Props

PropTypeDefaultDescription
showArrowbooleanfalseRender the SVG arrow caret pointing at the trigger.
side"top" | "right" | "bottom" | "left""bottom"Preferred placement. Radix flips automatically when space is tight.
sideOffsetnumber2.5Distance in pixels from the trigger. The component adds 5 extra when showArrow is false.
classNamestring-Tailwind classes merged with the component's CVA classes via cn().
childrenReact.ReactNode-Short hint text. Wraps at max-w-[200px].

Variants

VariantOptionsDefaultDescription
variant"primary" "neutral" "inverse" "danger" "info""primary"Color intent for the chip background, text, and arrow fill.

TooltipProvider

Wraps Radix's Tooltip.Provider. The bundled Tooltip already self-provides, so this export is only useful when you compose raw TooltipPrimitive.Root components and want shared defaults on a subtree. Extends React.ComponentProps<typeof TooltipPrimitive.Provider>.

Props

PropTypeDefaultDescription
delayDurationnumber-Default hover delay for descendant tooltips that don't set their own.
skipDelayDurationnumber300Window during which a follow-up tooltip opens without the standard delay (toolbar hover-through).
disableHoverableContentboolean-Prevent descendant tooltip content from staying open when the pointer moves over it.
childrenReact.ReactNode-The subtree that should inherit these defaults.