Tooltip

A small label that appears on hover or keyboard focus to explain an element. Use for icon-only buttons, truncated text, and keyboard shortcuts. Requires <TooltipProvider> as an ancestor. Built on @base-ui/react/tooltip.

Anatomy

TooltipProvider sets the shared delay for all descendant tooltips. Each Tooltip wraps a TooltipTrigger and a TooltipContent. The content includes a built-in positional arrow.

TooltipProvider (ancestor)TooltipTriggerTooltipContent + arrow

Positioning

The side prop controls which side the tooltip appears on (default: "top"). Auto-flips when space is insufficient.

side="top"
side="right"
side="bottom"
side="left"

Delay

TooltipProvider accepts a delay prop (ms) applied to all descendant tooltips. Override per-tooltip by wrapping in a separate provider.

delay={0} — instant

Best for persistent toolbars.

delay={500} — delayed

Reduces noise on hover-heavy UIs.

Examples

Icon toolbar

With keyboard shortcut

Truncated text

This is a very long filename that gets truncated.txt

Design Guidelines

Do

  • Use for icon-only buttons. Every icon button without a visible label needs a tooltip to communicate its action.
  • Include keyboard shortcuts in content. Showing ⌘K or Ctrl+S beside the label teaches users the shortcut naturally.
  • Keep content to one short phrase. Tooltips are supplemental — one line max.

Don't

  • Don't put interactive content inside. Links and buttons inside a tooltip are unreachable on touch devices — use Popover instead.
  • Don't use for required instructions. Tooltip content is only visible on hover/focus — never put information users must act on.
  • Don't wrap elements that are already labelled. If the button has visible text, a tooltip is redundant noise.

Developer Reference

Accessibility

  • role="tooltip" on the content — linked to the trigger via aria-describedby.
  • Tooltip is shown on keyboard focus (:focus-visible) in addition to hover — keyboard users see it.
  • TooltipProvider must wrap all tooltip usage — it controls the shared delay and manages group hover behaviour.
  • Arrow element is automatically positioned by the Base UI popup engine.

Usage

import {
  TooltipProvider,
  Tooltip,
  TooltipTrigger,
  TooltipContent,
} from "@/components/ui/tooltip"

// Wrap your app (or section) with TooltipProvider
<TooltipProvider>
  {/* Basic tooltip */}
  <Tooltip>
    <TooltipTrigger asChild>
      <Button variant="ghost" size="sm" aria-label="Bold">
        <Bold className="size-4" />
      </Button>
    </TooltipTrigger>
    <TooltipContent>
      <p>Bold</p>
    </TooltipContent>
  </Tooltip>

  {/* With keyboard shortcut */}
  <Tooltip>
    <TooltipTrigger asChild>
      <Button aria-label="Copy">
        <Copy className="size-4" />
      </Button>
    </TooltipTrigger>
    <TooltipContent>
      <p className="flex items-center gap-2">
        Copy <kbd className="rounded bg-muted px-1 text-xs">⌘C</kbd>
      </p>
    </TooltipContent>
  </Tooltip>
</TooltipProvider>

// Custom delay
<TooltipProvider delay={500}>...</TooltipProvider>

// Positioning
<TooltipContent side="right" align="start">...</TooltipContent>