Skip to content

Tooltip

Stable

A short text label that appears on hover and keyboard focus to name an icon-only control or reveal its shortcut.

Installation

$ pnpm dlx shadcn@latest add https://www.prfct.dev/r/tooltip.json

Wrap your app once in TooltipProvider. It gives every tooltip the same delay and lets neighbors open instantly once one is showing — hover along a toolbar and the labels follow without waiting.

app/layout.tsx
import { TooltipProvider } from "@/components/ui/tooltip"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <TooltipProvider delay={400}>{children}</TooltipProvider>
      </body>
    </html>
  )
}

Usage

import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip"
<Tooltip>
  <TooltipTrigger render={<Button variant="outline" size="icon" aria-label="Add to library" />}>
    <PlusIcon />
  </TooltipTrigger>
  <TooltipContent>Add to library</TooltipContent>
</Tooltip>

prfct tooltips are inverted — gray-1 text on a gray-12 fill — so they read as a label on top of any surface in either mode, and enter faster than other popups (160ms) because they appear dozens of times per session.

Examples

Keyboard shortcuts

Tooltips are the natural place to teach shortcuts. Put a Kbd after the label; it restyles itself for the inverted surface. Hover along the toolbar: after the first tooltip opens, the next ones appear immediately.

Side

side places the tooltip on the top (default), right, bottom or left of its trigger. It flips automatically near the viewport edges.

Disabled triggers

A disabled button receives no pointer or focus events, so a tooltip on it could never open. Keep it reachable with focusableWhenDisabled and use the tooltip to explain what's missing.

Delay

The provider sets a 400ms delay for every tooltip. Override it per trigger with delay — shorter for dense tools people scan quickly, longer where accidental tooltips would get in the way.

Guidelines

When to use

  • To name icon-only buttons. Every icon button needs an aria-label; the tooltip shows the same text to sighted pointer users.
  • To reveal keyboard shortcuts for common actions.
  • To expand truncated text, such as a long file name.

When not to use

  • For information people need to complete a task — show it on the page. Tooltips are invisible until someone thinks to look.
  • For interactive content: links, buttons, inputs. Tooltips disappear when the pointer leaves — use a Popover.
  • For rich previews — use a Hover Card.
  • On touch-only interfaces, where there is no hover — make the label visible instead.

Write labels, not sentences

A tooltip is read in a glance: two to four words, sentence case, no trailing period. Describe the action, not the icon.

Duplicate D
Do.Names the action in a few words, with its shortcut.
Click this copy icon button to make a duplicate copy of the selected item.
Don’t.Describes the icon and explains too much — nobody reads it.

Accessibility

A tooltip is a visual hint for sighted pointer and keyboard users. It opens on hover and on keyboard focus and never takes focus itself — but Base UI doesn't wire it to the trigger with aria-describedby, so screen readers don't announce it. The trigger's own accessible name has to carry the meaning.

KeyBehavior
Tab
Focusing the trigger opens the tooltip after the delay.
Esc
Closes the tooltip without moving focus.
  • Put the label in the accessible name. Give icon-only triggers an aria-label with the same text as the tooltip. A tooltip supplements the name; it never replaces it.
  • Hoverable. Moving the pointer onto the tooltip keeps it open, so people using screen magnification can read it (WCAG 1.4.13). Set disableHoverablePopup only for tooltips that follow the cursor.
  • Dismissible. Esc hides it without moving the pointer or focus.
  • Plain text only. Content inside a tooltip isn't reachable with the keyboard; never put links or buttons in it.

API reference

TooltipProvider

Shares a delay between tooltips. Doesn't render an element.

PropTypeDefault
delay

How long to wait before opening a tooltip on hover, in ms.

number400
closeDelay

How long to wait before closing a tooltip, in ms.

number0
timeout

After a tooltip closes, others open instantly within this window, in ms.

number400

Tooltip

The root. Doesn't render an element. Accepts every prop of Base UI Tooltip.Root.

PropTypeDefault
open

Whether the tooltip is open. Use with onOpenChange to control it.

booleanNo default
defaultOpen

Whether it is open initially, when uncontrolled.

booleanfalse
onOpenChange

Called when it opens or closes.

(open: boolean, details) => voidNo default
disabled

Prevents the tooltip from opening.

booleanfalse
disableHoverablePopup

Closes the tooltip as soon as the pointer leaves the trigger.

booleanfalse
trackCursorAxis

Makes the tooltip follow the cursor along an axis.

"none" | "x" | "y" | "both""none"

TooltipTrigger

The element that shows the tooltip. Renders a <button>; use render to render a prfct Button.

PropTypeDefault
delay

Overrides the provider's open delay for this trigger, in ms.

numberNo default
closeDelay

Overrides the close delay, in ms.

number0
closeOnClick

Closes the tooltip when the trigger is clicked.

booleantrue
disabled

Prevents this trigger from opening the tooltip. Doesn't disable the element.

booleanfalse

TooltipContent

Renders the portal, positioner and inverted popup with an arrow.

PropTypeDefault
side

Preferred side of the trigger. Flips when it doesn't fit.

"top" | "right" | "bottom" | "left" | "inline-start" | "inline-end""top"
sideOffset

Distance from the trigger, in px.

number6
align

Alignment against the trigger.

"start" | "center" | "end""center"
alignOffset

Offset along the alignment axis, in px.

number0