Tooltip
A small text hint shown on hover or focus to clarify a control.
@garn/ui/tooltipOn this page
Default
Provider → tooltip on a button.
Installation
garn is copy-in — the garn CLI writes this component's source into your project, so you own and can edit it. It resolves any base files and installs the npm dependencies below for you.
npx garn-ui add tooltip- Registry
tooltip- Deps
@radix-ui/react-tooltip- Registry deps
utils
Import
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "@garn/ui/tooltip";Anatomy
The parts this component is built from — compose them to assemble it.
TooltipProviderRequiredWraps the app (or a subtree) once; shares delay/skip config across tooltips.
TooltipRequiredRoot — owns the open state for one tooltip.
TooltipTriggerRequired[data-slot="tooltip-trigger"]The element the hint describes (asChild to wrap your control).
TooltipContentRequired[data-slot="tooltip-content"]The hint bubble (portaled, non-interactive).
Props
The component's public props and their types.
No component-specific props — this is a thin wrapper over its native element.
Styling
Target these data-slots and states, and remap these tokens, to restyle without forking the component.
[data-slot="tooltip-content"]States
| Selector | State | Description |
|---|---|---|
[data-state=delayed-open] | delayed-open | Shown after the hover delay. |
[data-state=instant-open] | instant-open | Shown immediately (skip-delay window). |
[data-state=closed] | closed |
| Property | Token | Tier |
|---|---|---|
fill | --garn-brand-solidbrandable | semantic |
motion | --garn-motion-fast | semantic |
When to use
Add a brief, supplementary text hint to a control — clarify an icon button, abbreviate a label, surface a shortcut.
Reach for something else when
- Essential information the user must read (put it inline)
- interactive content like links/buttons (use a popover)
- a control's primary label (use a real label / aria-label).
Overview
Tooltip adds a brief, supplementary text hint to a control — naming an icon button, spelling out an abbreviation, surfacing a shortcut. Wrap the app (or a subtree) once in a TooltipProvider to share delay/skip timing, then each Tooltip pairs a TooltipTrigger with a non-interactive TooltipContent. It's a passive label, not a surface you can click into — for interactive content use Popover, for a profile/link preview use HoverCard.
Guidelines
Never put essential or interactive content in a tooltip. It's keyboard- and touch-hostile by nature — no clicks, no links, and it can be missed entirely. Anything required to complete the task belongs in the visible UI; the tooltip only supplements.
A tooltip supplements a name, it doesn't replace one. An icon-only button still needs its own aria-label — the tooltip is a hover convenience, not the accessible name. Keep the text to a few words, no rich formatting.
Use one Provider and lean on its timing. A single TooltipProvider keeps delays consistent and the skip-delay snappy when moving between controls. Don't trigger tooltips on disabled elements that can't receive focus — wrap an enabled element instead.
Best practices
- Keep it to a few words; mount one TooltipProvider near the app root.
- Still give icon-only triggers an aria-label — the tooltip is extra, not the name.
- Don't put interactive elements in a tooltip — it can't be focused/clicked reliably.
- Don't hide critical information behind hover only.
Content guidelines
- Keep it to a short, supplementary phrase — a name or a shortcut, not a sentence.
- Don't put essential information in a tooltip, and don't just restate the visible label.
Troubleshooting
The tooltip never appears, or only on the first one.
Cause. No TooltipProvider ancestor wrapping the Tooltip(s).
Fix. Mount a single <TooltipProvider> near the app root (or wrap the subtree).
Accessibility
- Role
tooltip- ARIA APG
- tooltip
- Focus
- Appears on trigger focus, not just hover; dismissible with Escape.
Accessibility requirements
Give the trigger its own accessible name (aria-label); the tooltip is supplementary, not a label.
when the trigger is an icon-only control that relies on the tooltip for its only accessible name
Wrap the app (or subtree) in a single TooltipProvider.
when a Tooltip is rendered without a TooltipProvider ancestor
Keyboard
| Tab | Focusing the trigger shows the tooltip. |
| Escape | Dismiss the tooltip while the trigger stays focused. |
- Trigger is described by the tooltip (aria-describedby); shows on hover AND keyboard focus.
- Content is non-interactive — never put links/buttons inside a tooltip (use a popover).