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.jsonThis 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)
└── TooltipContentTooltipProvider 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
| Setting | Default |
|---|---|
| Hover delay | 400ms; configurable on Provider or Tooltip |
| Gap from trigger | 4px |
| Viewport padding | 8px |
| Maximum width | 20rem, constrained by available space |
| Text | 12px / 16px |
| Surface | Foreground color with background-colored text |
| Elevation | Subtle 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.