Skip to content

shadcn.io is an independent project built on shadcn/ui

Components

Free

Tooltip for Radix UI

A hover label for an icon button that shows the same line on keyboard focus. For React with Radix UI, when the action isn't written on the screen.

One short line shows on hover or focus, then it goes away. Don't put a link in it.

Use it when the control doesn't already say what it does, like an icon button. If the pointer should enter the content, use a Hover Card. In React, Radix UI opens it on hover and keyboard focus, and a phone user can miss it.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.
Use email insteadNo credit card

Anatomy

Tooltip anatomy: content, positioner, arrow, trigger
TooltipTrigger
TooltipArrow
โ””โ”€โ”€ TooltipArrowTip
TooltipContent
โ””โ”€โ”€ TooltipPositioner

Usage

import { Button } from "@/components/ui/button";
import {
  Tooltip, TooltipContent, TooltipTrigger,
} from "@/components/ui/tooltip";
<Tooltip>
  <TooltipTrigger asChild>
    <Button variant="outline">Hover</Button>
  </TooltipTrigger>
  <TooltipContent>
    <p>Add to library</p>
  </TooltipContent>
</Tooltip>

Accessibility

Tab
Opens/closes the tooltip without delay.
Escape
If open, closes the tooltip without delay.
Enter
Activate the focused item.
Space
Activate the focused control.

Demos

Sides

The same label, Add to library, opens on the left, the top, the bottom, and the right. The default is the top, and it should flip when there is no room, but you pin a side when the default would cover the thing the person is editing. Pick the side with empty space, not the side that looks balanced on an empty page.

Preview width

Keyboard

The button is only a save icon. Its accessible name is Save Changes, and the tooltip repeats that name next to the S shortcut. Use this when an icon button has a keyboard equivalent worth advertising. The shortcut shown here is a hint, not the binding, so you still register the key yourself.

Preview width

Disabled

A disabled button receives no hover or focus, so a tooltip wrapped around it never opens. Here the trigger is a span around the button, and that span takes the pointer. The label says the feature is unavailable. Wrap like this when people need the reason, and otherwise leave the button focusable and ignore the click.

Preview width

Rtl

The first of two rows is the physical sides, labeled in Arabic. The second is labeled as the start and the end of the line, while the placement values are still left and right, so you can see those edges under a right-to-left page. The tooltip text is Arabic too. Set direction on the container when the page itself is not already right to left.

Preview width

FAQ

How do I change the Tooltip delay in React?

Set the delay where the base reads it; a provider sets it once for every tooltip inside it. Use delayDuration on Tooltip, or on the TooltipProvider.

Do I need a TooltipProvider with Radix UI?

Yes: Radix UI tooltips must be inside a TooltipProvider, as the default demo does. Put one near the root of your app.

How do I change which side the Tooltip appears on?

It opens on top by default and flips when there is not enough room; the Sides demo shows all four sides. Set side on TooltipContent, for example bottom.

Why doesn't the Tooltip show on a disabled button?

A disabled button gets no pointer or focus events, so it cannot open a Tooltip. Wrap the button in a span, as the Disabled demo does, so the span receives the hover; or keep the button enabled with aria-disabled and ignore its clicks.

Does the Tooltip work on mobile and touch screens?

Not as a hover hint: touch screens have no hover, so a Tooltip mostly shows when its trigger gets focus. For information people must be able to read on a phone, use a Toggle Tooltip, which opens on tap.

Is the Tooltip accessible to keyboard and screen reader users?

Yes. It opens when its trigger gets keyboard focus and closes on Escape, as the Keyboard demo shows. Keep tooltip text short and never put links or buttons inside it. Its text is linked to the trigger as its description, so screen readers read it after the trigger's name.

How do I install the Tooltip in React?

Run the command in the Installation section above: it adds the Tooltip to your ui folder. The command uses the shadcn CLI.

API Reference

Tooltip

data-slot="tooltip"

PropType
open?boolean

Whether it's open. Pair with onOpenChange to control it.

defaultOpen?boolean

Whether it starts open, when you don't control open.

onOpenChange?{ bivarianceHack(open: boolean): void; }["bivarianceHack"]

Called when it opens or closes.

Type
{ bivarianceHack(open: boolean): void; }["bivarianceHack"]
delayDuration?number

The duration from when the pointer enters the trigger until the tooltip gets opened. This will override the prop with the same name passed to Provider.

disableHoverableContent?boolean

When true, trying to hover the content will result in the tooltip closing as the pointer leaves the trigger.

TooltipTrigger

<button> data-slot="tooltip-trigger"

PropType
asChild?boolean

Merge props onto the child element instead of rendering a host.

TooltipArrow

<div> data-slot="tooltip-arrow"

CSS variableType
--radix-tooltip-content-transform-originstring

TooltipContent

<div> data-slot="tooltip-content"

PropType
align?(typeof ALIGN_OPTIONS)[number]

How it lines up with the trigger: start, center or end.

alignOffset?number

How far it shifts from its align position, in px.

arrowPadding?number

The space kept between the arrow and the content's corners, in px.

avoidCollisions?boolean

Whether it flips and shifts to stay in view.

collisionBoundary?Boundary | Boundary[]

The element or elements it stays inside. The viewport when unset.

Type
Boundary | Boundary[]
collisionPadding?number | Partial<Record<Side, number>>

The distance it keeps from the boundary's edges, in px, or one per side.

Type
number | Partial<Record<Side, number>>
forceMount?true

Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries.

hideWhenDetached?boolean

Whether it hides when its trigger is entirely out of view.

onEscapeKeyDown?{ bivarianceHack(event: KeyboardEvent): void; }["bivarianceHack"]

Event handler called when the escape key is down. Can be prevented.

Type
{ bivarianceHack(event: KeyboardEvent): void; }["bivarianceHack"]
onPointerDownOutside?{ bivarianceHack(event: PointerDownOutsideEvent): void; }["bivarianceHack"]

Event handler called when the a pointerdown event happens outside of the Tooltip. Can be prevented.

Type
{ bivarianceHack(event: PointerDownOutsideEvent): void; }["bivarianceHack"]
side?(typeof SIDE_OPTIONS)[number]

The side of the trigger it opens on. It flips when there's no room, unless avoidCollisions is off.

sideOffset?number

The distance from the trigger, in px.

Default
4
sticky?(typeof Sticky)[keyof typeof Sticky]

How it stays in view along its trigger: partial while the trigger is partly visible, always whatever the trigger does.

Type
(typeof Sticky)[keyof typeof Sticky]
updatePositionStrategy?(typeof UpdatePositionStrategy)[keyof typeof UpdatePositionStrategy]

How often it updates its position: optimized, on layout changes, or always, every animation frame.

Type
(typeof UpdatePositionStrategy)[keyof typeof UpdatePositionStrategy]
asChild?boolean

Merge props onto the child element instead of rendering a host.

className?string

Merged with the part's classes.

AttributeType
data-instant?string

Present when instant is true.

data-placementstring

The content's placement on its trigger, such as bottom-start.

data-side"top" | "right" | "bottom" | "left"

The side of the trigger the content sits on.

Type
"top" | "right" | "bottom" | "left"
data-state"open" | "closed"

"open" or "closed".

Type
"open" | "closed"
CSS variableType
--radix-tooltip-content-transform-originstring

TooltipProvider

data-slot="tooltip-provider"

PropType
delayDuration?number

The duration from when the pointer enters the trigger until the tooltip gets opened.

Default
0
disableHoverableContent?boolean

When true, trying to hover the content will result in the tooltip closing as the pointer leaves the trigger.

skipDelayDuration?number

How much time a user has to enter another trigger without incurring a delay again.