Tooltip
A popup that displays additional information when hovering over a trigger element.
Installation
$
Usage
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip"Examples
Default
Positioning
Control where the tooltip shows with side (top/right/bottom/left) and align (start/center/end) on TooltipContent; both pass straight through to Base UI's positioner. Pick a cell and the code below updates to match your selection.
Tooltip placement
side="top" align="center"
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| sideTooltipContent | "top" | "right" | "bottom" | "left" | "top" | Preferred edge of the trigger to render against. |
| alignTooltipContent | "start" | "center" | "end" | "center" | Alignment against the trigger along the chosen side. |
| sideOffsetTooltipContent | number | 6 | Distance in pixels between the tooltip and the trigger. |
| collisionAvoidanceTooltipContent | CollisionAvoidance | { fallbackAxisSide: "end" } | Object controlling how the tooltip avoids viewport collisions on the side and alignment axes, e.g. { side: 'none', align: 'none' } to always honor side/align. |
| delayTooltip | number | 300 | Delay in ms before the tooltip opens on hover. Each Tooltip wraps its own TooltipProvider, so an app-level provider's value won't apply. |
"use client"
import * as React from "react"
import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
import { cn } from "@/registry/lib/utils"
function TooltipProvider({
delay = 300,
...props
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
return (
<TooltipPrimitive.Provider data-slot="tooltip-provider" delay={delay} {...props} />
)
}
function Tooltip({
...props
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
return (
<TooltipProvider>
<TooltipPrimitive.Root data-slot="tooltip" {...props} />
</TooltipProvider>
)
}
function TooltipTrigger({
...props
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
}
function TooltipContent({
className,
sideOffset = 6,
side,
align,
alignOffset,
collisionAvoidance,
children,
...props
}: React.ComponentProps<typeof TooltipPrimitive.Popup> &
Pick<
React.ComponentProps<typeof TooltipPrimitive.Positioner>,
"side" | "align" | "sideOffset" | "alignOffset" | "collisionAvoidance"
>) {
return (
<TooltipPrimitive.Portal>
{/* z-50 goes on the Positioner, not the Popup: the Popup is
`position: static`, where z-index has no effect. See DropdownMenu. */}
<TooltipPrimitive.Positioner
className="z-50"
side={side}
align={align}
sideOffset={sideOffset}
alignOffset={alignOffset}
collisionAvoidance={collisionAvoidance}
>
<TooltipPrimitive.Popup
data-slot="tooltip-content"
className={cn(
// Inverted, arrow-less hint - consistent with the kit's other overlays
// (none use an arrow). Subtle ease-out enter: fade + small scale + a
// short slide away from the trigger.
"bg-foreground text-background transition-[opacity,scale,translate] motion-reduce:transition-[opacity] ease-out duration-150 data-[instant]:duration-0 data-[starting-style]:opacity-0 data-[ending-style]:opacity-0 data-[starting-style]:scale-95 data-[ending-style]:scale-95 data-[side=bottom]:data-[starting-style]:-translate-y-1 data-[side=bottom]:data-[ending-style]:-translate-y-1 data-[side=top]:data-[starting-style]:translate-y-1 data-[side=top]:data-[ending-style]:translate-y-1 data-[side=right]:data-[starting-style]:-translate-x-1 data-[side=right]:data-[ending-style]:-translate-x-1 data-[side=left]:data-[starting-style]:translate-x-1 data-[side=left]:data-[ending-style]:translate-x-1 w-fit origin-(--transform-origin) rounded-md px-2.5 py-1.5 text-xs font-medium text-balance shadow-md",
className
)}
{...props}
>
{children}
</TooltipPrimitive.Popup>
</TooltipPrimitive.Positioner>
</TooltipPrimitive.Portal>
)
}
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }