import { Tooltip, TooltipContent, TooltipTrigger } from "@registry/components/ui/tooltip";
import { Button } from "@registry/components/ui/button";
export function TooltipExample() {
return (
<Tooltip>
<TooltipTrigger render={<Button variant="outline">Hover me</Button>} />
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
);
} Examples
Positioning
Use positionerProps on TooltipContent to control which side the tooltip appears on.
import { Tooltip, TooltipContent, TooltipTrigger } from "@registry/components/ui/tooltip";
import { Button } from "@registry/components/ui/button";
export function TooltipPositionedExample() {
return (
<div className="flex flex-wrap items-center gap-4">
<Tooltip>
<TooltipTrigger render={<Button variant="outline">Top</Button>} />
<TooltipContent positionerProps={{ side: "top" }}>
<p>Tooltip on top</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger render={<Button variant="outline">Bottom</Button>} />
<TooltipContent positionerProps={{ side: "bottom" }}>
<p>Tooltip on bottom</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger render={<Button variant="outline">Left</Button>} />
<TooltipContent positionerProps={{ side: "left" }}>
<p>Tooltip on left</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger render={<Button variant="outline">Right</Button>} />
<TooltipContent positionerProps={{ side: "right" }}>
<p>Tooltip on right</p>
</TooltipContent>
</Tooltip>
</div>
);
} Hover delay
Control the open delay with the delay prop on TooltipTrigger.
import { Tooltip, TooltipContent, TooltipTrigger } from "@registry/components/ui/tooltip";
import { Button } from "@registry/components/ui/button";
export function TooltipWithDelayExample() {
return (
<div className="flex flex-wrap items-center gap-4">
<Tooltip>
<TooltipTrigger delay={0} render={<Button variant="outline">Instant</Button>} />
<TooltipContent>
<p>Appears immediately</p>
</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger delay={500} render={<Button variant="outline">Delayed</Button>} />
<TooltipContent>
<p>Appears after 500ms</p>
</TooltipContent>
</Tooltip>
</div>
);
} Animated shared tooltip
Use createTooltipHandle with TooltipProvider to share a single tooltip across multiple triggers. The TooltipViewport component animates the content when moving between triggers.
import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider, TooltipViewport, createTooltipHandle } from "@registry/components/ui/tooltip";
import { Button } from "@registry/components/ui/button";
import { PencilSimpleIcon, TrashIcon, CopyIcon, DownloadSimpleIcon, ShareNetworkIcon } from "@phosphor-icons/react";
export function TooltipAnimatedExample() {
const tooltipHandle = createTooltipHandle<string>();
return (
<TooltipProvider>
<div className="flex items-center gap-2">
<TooltipTrigger
handle={tooltipHandle}
payload="Edit this item"
render={
<Button size="icon" variant="ghost">
<PencilSimpleIcon />
</Button>
}
/>
<TooltipTrigger
handle={tooltipHandle}
payload="Duplicate"
render={
<Button size="icon" variant="ghost">
<CopyIcon />
</Button>
}
/>
<TooltipTrigger
handle={tooltipHandle}
payload="Download"
render={
<Button size="icon" variant="ghost">
<DownloadSimpleIcon />
</Button>
}
/>
<TooltipTrigger
handle={tooltipHandle}
payload="Share"
render={
<Button size="icon" variant="ghost">
<ShareNetworkIcon />
</Button>
}
/>
<TooltipTrigger
handle={tooltipHandle}
payload="Delete"
render={
<Button size="icon" variant="ghost">
<TrashIcon />
</Button>
}
/>
</div>
<Tooltip handle={tooltipHandle}>
{({ payload }) => (
<TooltipContent>
{typeof payload === "string" && (
<TooltipViewport>
<span>{payload}</span>
</TooltipViewport>
)}
</TooltipContent>
)}
</Tooltip>
</TooltipProvider>
);
} Installation
Copy the source code below into your project:
import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
import { cn } from "@registry/lib/utils";
const createTooltipHandle = BaseTooltip.createHandle;
function Tooltip({ children, ...props }: BaseTooltip.Root.Props) {
return (
<BaseTooltip.Root data-slot="tooltip" {...props}>
{children}
</BaseTooltip.Root>
);
}
function TooltipProvider({ ...props }: BaseTooltip.Provider.Props) {
return <BaseTooltip.Provider data-slot="tooltip-provider" {...props} />;
}
function TooltipTrigger({ delay = 100, ...props }: BaseTooltip.Trigger.Props) {
return <BaseTooltip.Trigger delay={delay} data-slot="tooltip-trigger" {...props} />;
}
function TooltipContent({
className,
children,
positionerProps,
portalProps,
...props
}: BaseTooltip.Popup.Props & {
positionerProps?: BaseTooltip.Positioner.Props;
portalProps?: BaseTooltip.Portal.Props;
}) {
return (
<BaseTooltip.Portal {...portalProps}>
<BaseTooltip.Positioner
alignOffset={positionerProps?.alignOffset || 0}
className={cn(
"outline-none",
"h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom,transform] duration-[0.35s] ease-[cubic-bezier(0.22,1,0.36,1)] data-instant:transition-none",
positionerProps?.className,
)}
side={positionerProps?.side || "top"}
sideOffset={positionerProps?.sideOffset || 4}
{...positionerProps}
>
<BaseTooltip.Popup
className={cn(
"flex h-(--popup-height,auto) w-(--popup-width,auto) origin-(--transform-origin) flex-col rounded-lg bg-gray-900 px-3 py-2 text-sm text-gray-50 transition-[transform,scale,opacity] data-ending-style:scale-90 data-ending-style:opacity-0 data-instant:duration-0 data-starting-style:scale-90 data-starting-style:opacity-0 dark:outline dark:-outline-offset-1 dark:outline-gray-700",
className,
)}
data-slot="tooltip-popup"
{...props}
>
{children}
</BaseTooltip.Popup>
</BaseTooltip.Positioner>
</BaseTooltip.Portal>
);
}
function TooltipViewport({
children,
className: _className,
...props
}: BaseTooltip.Viewport.Props) {
return (
<BaseTooltip.Viewport
className="relative h-full w-full overflow-clip px-(--viewport-inline-padding) py-1 [--viewport-inline-padding:0.5rem] **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding))] **:data-current:translate-x-0 **:data-current:opacity-100 **:data-current:transition-[translate,opacity] **:data-current:duration-[350ms,175ms] **:data-current:ease-[cubic-bezier(0.22,1,0.36,1)] **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding))] **:data-previous:translate-x-0 **:data-previous:opacity-100 **:data-previous:transition-[translate,opacity] **:data-previous:duration-[350ms,175ms] **:data-previous:ease-[cubic-bezier(0.22,1,0.36,1)] data-[activation-direction~='left']:[&_[data-current][data-starting-style]]:-translate-x-1/2 data-[activation-direction~='left']:[&_[data-current][data-starting-style]]:opacity-0 data-[activation-direction~='right']:[&_[data-current][data-starting-style]]:translate-x-1/2 data-[activation-direction~='right']:[&_[data-current][data-starting-style]]:opacity-0 data-[activation-direction~='left']:[&_[data-previous][data-ending-style]]:translate-x-1/2 data-[activation-direction~='left']:[&_[data-previous][data-ending-style]]:opacity-0 data-[activation-direction~='right']:[&_[data-previous][data-ending-style]]:-translate-x-1/2 data-[activation-direction~='right']:[&_[data-previous][data-ending-style]]:opacity-0 [[data-instant]_&_[data-current]]:transition-none [[data-instant]_&_[data-previous]]:transition-none"
data-slot="tooltip-viewport"
{...props}
>
{children}
</BaseTooltip.Viewport>
);
}
export {
Tooltip,
TooltipProvider,
TooltipTrigger,
TooltipContent,
TooltipViewport,
createTooltipHandle,
}; API Reference
Tooltip
This component does not add any props on top of Base UI Tooltip.Root . See the Base UI docs for the full API reference.
TooltipTrigger
The TooltipTrigger component extends the Base UI Tooltip.Trigger
props and adds the following:
| Prop | Type | Default | Description |
|---|---|---|---|
| delay | number | 100 | Delay in milliseconds before the tooltip opens. |
TooltipContent
The TooltipContent component extends the Base UI Tooltip.Popup
props and adds the following:
| Prop | Type | Default | Description |
|---|---|---|---|
| positionerProps | BaseTooltip.Positioner.Props | — | Props forwarded to the underlying Positioner component. Includes align, side, sideOffset, alignOffset, collisionPadding, etc. |
| portalProps | BaseTooltip.Portal.Props | — | Props forwarded to the underlying Portal component. |
TooltipViewport
This component does not add any props on top of Base UI Tooltip.Viewport . See the Base UI docs for the full API reference.
TooltipProvider
This component does not add any props on top of Base UI Tooltip.Provider . See the Base UI docs for the full API reference.