Tooltip
A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
Installation
Install the following dependencies:
Set up the token layer and the StyleX compiler, if you have not already. See
Installation, and paste states.ts and state-styles.ts
from the same page. states.ts provides the positioner's layer, and
state-styles.ts is how the popup and its arrow read their Base UI state.
Copy and paste the following code into your project.
Update the import paths to match your project setup.
Wrap your app in the TooltipProvider.
Usage
Composition
TooltipTrigger renders a <button>. Pass render to use a different element
as the trigger, such as a Button variant.
Every tooltip inside the provider shares its delay. While one is open, moving
to a neighbour opens the next one with no delay and no transition.
A tooltip opens on hover and on keyboard focus, never on press. A touch screen
has no hover, so the tooltip never opens there. Put nothing in it that a reader
cannot also reach another way, and give an icon-only trigger an aria-label of
its own rather than relying on the tooltip's text.
Side
Use side on TooltipContent to pick the edge it opens from. Base UI flips the
side when there is no room, and the arrow follows.
Disabled button
A disabled button fires no pointer events, so wrap it in a <span> and make
the span the trigger.
Keyboard shortcut
Put a Kbd in the content to show the shortcut beside
the label.
API reference
Pass render to replace a part's element or compose it with another component.
Every part wraps the Base UI Tooltip part of the same name and accepts its
props. See the Base UI reference
for the full list. TooltipContent also takes xstyle and className, and
style for real inline CSS, merged over whatever its Base UI state resolves
to.
TooltipProvider
| Prop | Type | Default |
|---|---|---|
delay | number | 0 |
closeDelay | number | — |
timeout | number | 400 |
timeout is how long after one tooltip closes the next one still opens
instantly.
Tooltip
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
defaultOpen | boolean | false |
onOpenChange | (open: boolean, details) => void | — |
disabled | boolean | false |
disableHoverablePopup | boolean | false |
trackCursorAxis | "none" | "x" | "y" | "both" | "none" |
handle | TooltipHandle | — |
TooltipTrigger
| Prop | Type | Default |
|---|---|---|
delay | number | 600 |
closeDelay | number | 0 |
closeOnClick | boolean | true |
disabled | boolean | false |
payload | Payload | — |
A delay on the trigger is only read when the provider sets none.
TooltipContent
| Prop | Type | Default |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "top" |
sideOffset | number | 4 |
align | "start" | "center" | "end" | "center" |
alignOffset | number | 0 |
style | CSSProperties | — |
The popup is as wide as its text and wraps past 20rem. Change the width
through xstyle.
Data attributes
| Attribute | On | Effect |
|---|---|---|
data-slot="tooltip-content" | the popup | Popup surface |
data-slot="tooltip-arrow" | the arrow | Positioned by Base UI on the cross axis, by the side on ours |
data-side, data-align | both | Which way the popup slides in from, and where the arrow sits |
data-instant | the popup | Base UI writes it when the transition is skipped |
data-starting-style, data-ending-style | the popup | Base UI writes them while the popup animates |
data-popup-open | the trigger | Base UI writes it while this trigger's tooltip is open |