Tooltip
A popup that displays information related to an element when the element receives focus or is hovered.
Basic Usage
import { TooltipContent, TooltipTrigger } from "@repo/ui/components/tooltip";
import { Button } from "@repo/ui/components/button";
/* BASIC USAGE EXAMPLE */
export const Example1 = () => {
return (
<TooltipTrigger>
<Button variant="outline">Hover me</Button>
<TooltipContent>Add to library</TooltipContent>
</TooltipTrigger>
);
};
Placement
import { TooltipContent, TooltipTrigger } from "@repo/ui/components/tooltip";
import { Button } from "@repo/ui/components/button";
/* TOOLTIP PLACEMENT EXAMPLE */
export const Example2 = () => {
return (
<div className="flex flex-wrap items-center justify-center gap-4">
<TooltipTrigger>
<Button variant="outline">Top</Button>
<TooltipContent placement="top">Top tooltip</TooltipContent>
</TooltipTrigger>
<TooltipTrigger>
<Button variant="outline">Bottom</Button>
<TooltipContent placement="bottom">
Bottom tooltip
</TooltipContent>
</TooltipTrigger>
<TooltipTrigger>
<Button variant="outline">Left</Button>
<TooltipContent placement="left">Left tooltip</TooltipContent>
</TooltipTrigger>
<TooltipTrigger>
<Button variant="outline">Right</Button>
<TooltipContent placement="right">Right tooltip</TooltipContent>
</TooltipTrigger>
</div>
);
};
With Icon Buttons
import { TooltipContent, TooltipTrigger } from "@repo/ui/components/tooltip";
import { Button } from "@repo/ui/components/button";
import { Info, HelpCircle, Settings } from "lucide-react";
/* TOOLTIP WITH ICON BUTTONS */
export const Example3 = () => {
return (
<div className="flex items-center gap-2">
<TooltipTrigger>
<Button variant="ghost" size="icon">
<Info className="size-4" />
</Button>
<TooltipContent>More information</TooltipContent>
</TooltipTrigger>
<TooltipTrigger>
<Button variant="ghost" size="icon">
<HelpCircle className="size-4" />
</Button>
<TooltipContent>Help & Support</TooltipContent>
</TooltipTrigger>
<TooltipTrigger>
<Button variant="ghost" size="icon">
<Settings className="size-4" />
</Button>
<TooltipContent>Settings</TooltipContent>
</TooltipTrigger>
</div>
);
};
Component Code
"use client";
import React from "react";
import {
Tooltip as AriaTooltip,
TooltipTrigger as AriaTooltipTrigger,
TooltipProps as AriaTooltipProps,
TooltipTriggerComponentProps,
OverlayArrow,
composeRenderProps,
} from "react-aria-components";
import { tv } from "tailwind-variants";
import { cn } from "tailwind-variants";
const tooltipStyles = tv({
base: "bg-secondary text-secondary-foreground z-50 rounded-md px-3 py-1.5 text-xs shadow-md",
variants: {
isEntering: {
true: "animate-in fade-in-0 zoom-in-95 duration-200",
},
isExiting: {
true: "animate-out fade-out-0 zoom-out-95 duration-150",
},
},
});
export interface TooltipProps extends Omit<AriaTooltipProps, "children"> {
children: React.ReactNode;
}
export const TooltipTrigger = (props: TooltipTriggerComponentProps) => {
return <AriaTooltipTrigger delay={750} {...props} />;
};
export const TooltipContent = ({
children,
className,
...props
}: TooltipProps) => {
return (
<AriaTooltip
data-slot="tooltip"
offset={8}
{...props}
className={composeRenderProps(
className,
(className, renderProps) =>
cn(tooltipStyles({ ...renderProps }), className) || "",
)}
>
<OverlayArrow>
{({ placement }) => (
<svg
width={8}
height={8}
viewBox="0 0 8 8"
className={cn(
"fill-secondary scale-110",
placement?.startsWith("top") && "",
placement?.startsWith("bottom") && "-rotate-180",
placement?.startsWith("right") && "rotate-90",
placement?.startsWith("left") && "-rotate-90",
)}
>
<path d="M0 0 L4 4 L8 0" />
</svg>
)}
</OverlayArrow>
{children}
</AriaTooltip>
);
};