Tooltip

Brief, contextual help on hover or keyboard focus.

Preview

Hover over a trigger or reach it with Tab. Icon buttons keep an accessible name even when their tooltip is closed.

Installation

From a shadcn-initialized Radix project:

pnpm dlx shadcn@latest add http://127.0.0.1:3017/r/tooltip.json

This installs Tooltip source and its Radix dependency, preserving your existing theme. Button is a separate item used in these examples. The endpoint is a local snapshot; see the registry guide for reviewed updates.

The entrance and exit animations use tw-animate-css, as in a standard shadcn setup. Keep @import "tw-animate-css"; in the consuming app’s global stylesheet. The Tooltip item does not modify that stylesheet.

Usage

Place one provider around the app or a group of related tooltips. The provider coordinates the initial hover delay and subsequent tooltips. Use asChild to compose the trigger with your existing button rather than nesting buttons.

import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip';
import { Button } from '@/components/ui/button';

<TooltipProvider>
  <Tooltip>
    <TooltipTrigger asChild>
      <Button variant="outline">Add item</Button>
    </TooltipTrigger>
    <TooltipContent>Add this item to your library</TooltipContent>
  </Tooltip>
</TooltipProvider>

Composition

Place a provider around related tooltips, then give each tooltip a trigger and content:

TooltipProvider
└── Tooltip (repeat for each hint)
    ├── TooltipTrigger
    │   └── Button (via asChild)
    └── TooltipContent

TooltipProvider coordinates hover timing. Tooltip owns open state, TooltipTrigger identifies the control, and TooltipContent supplies the hint. Use Radix's asChild on the trigger to compose an existing button without nesting buttons. The content handles its portal and arrow internally; keep its children non-interactive.

Placement

Choose top, right, bottom, or left. Collision handling may change the final placement when space is limited.

<TooltipContent side="right" align="center">
  Position: right
</TooltipContent>

Disabled actions

Disabled buttons cannot receive focus or pointer events. Use a focusable wrapper as the trigger when an explanation is useful. Prefer visible helper text when the reason is essential to completing the task.

<Tooltip>
  <TooltipTrigger asChild>
    <span role="group" tabIndex={0} aria-label="Publish unavailable">
      <Button disabled>Publish</Button>
    </span>
  </TooltipTrigger>
  <TooltipContent>Add a title before publishing.</TooltipContent>
</Tooltip>

Appearance and behavior

SettingDefault
Hover delay400ms; configurable on Provider or Tooltip
Gap from trigger4px
Viewport padding8px
Maximum width20rem, constrained by available space
Text12px / 16px
SurfaceForeground color with background-colored text
ElevationSubtle shadow, reserved for this floating surface

The tooltip is portaled outside the preview container to avoid clipping. Long text wraps. Reduced-motion preferences disable its entrance and exit animation.

Accessibility

  • Tab focuses the trigger and opens its tooltip. Escape dismisses it.
  • Moving into the tooltip keeps it open; it closes when the pointer leaves both trigger and content.
  • Tooltip content supplements the trigger's accessible name. Always label icon-only controls independently.
  • Keep the content short and non-interactive. Use a popover for links, buttons, or richer content.
  • Do not hide essential instructions in a tooltip or depend on hover for touch users.

Based on shadcn Tooltip and Radix Tooltip.

On this page