- Accordion
- Agent Thinking
- Alert
- Alert Dialog
- Announcement
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Calendar
- Card
- Carousel
- Checkbox
- Checkbox Card
- Code Block
- Collapsible
- Color Picker
- Combobox
- Command
- Composer
- Composer Loader
- Context Menu
- Data Grid
- Data Table
- Date Picker
- Dialog
- Direction
- Drawer
- Dropdown Menu
- Empty
- Field
- File Upload
- Hover Card
- Input
- Input Group
- Input Otp
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Message Scroller
- Meter
- Native Select
- Navigation Menu
- Number Field
- Pagination
- Period Switcher
- Popover
- Progress
- Questionnaire
- Radio Card
- Radio Group
- Resizable
- Reveal
- Scroll Area
- Search Field
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Social Button
- Sonner
- Spinner
- Status Dot
- Switch
- Switch Card
- Table
- Tabs
- Tag Group
- Textarea
- Theme Toggle
- Time Field
- Toggle
- Toggle Group
- Tooltip
- Trace
- Tree View
- Agent Creator 01
- Agent Limits Card 01
- Agent Progress 01
- AI Chat 01
- AI Image Generation 01
- AI Profile 01
- Alerts Card 01
- Auth Card 01
- Calendar 01
- Composer 01
- Composer Attachments 01
- Composer Panel 01
- Finance Dashboard 01
- Home Dashboard 01
- Marketing Dashboard 01
- Medical Profile 01
- Meeting Scheduler 01
- Multi Agent Chat 01
- Notification Center 01
- Patient Info Card 01
- Project Board 01
- Questionnaire 01
- Settings Modal 01
- Sidebar 01
- Stat Cards 01
- Task List 01
- Web Search 01
- Activity Rings Card 01
- Area Chart Card 01
- Bar List Card 01
- Combo Chart Card 01
- Contributions Card 01
- Earnings Chart Card 01
- Funnel Chart Card 01
- Heatmap Chart Card 01
- Line Chart Card 01
- Most Active Days Card 01
- Orders Chart Card 01
- Radar Chart Card 01
- Radial Chart Card 01
- Revenue Chart Card 01
- Sankey Chart Card 01
- Scatter Chart Card 01
- Sleep Score Card 01
- Stage Bars Card 01
- Steps Card 01
Installation
$ pnpm dlx shadcn@latest add @cobalt/tooltip
Defaults
The popup is a small text-only pill: a hairline border, a soft shadow and the popover surface in both themes. It opens below the trigger with a 10px gap and a small arrow, and fades, scales and blurs in and out over 200ms (no motion under reduced-motion). Pass side to place it elsewhere, or showArrow={false} to drop the arrow. For an icon button, use <Button tooltip="Label" /> instead of wiring Tooltip, TooltipTrigger and TooltipContent by hand.
Source
"use client";
import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
import { cn } from "cn";
function TooltipProvider({
delay = 0,
...props
}: TooltipPrimitive.Provider.Props) {
return (
<TooltipPrimitive.Provider
data-slot="tooltip-provider"
delay={delay}
{...props}
/>
);
}
function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
}
function TooltipTrigger({ ...props }: TooltipPrimitive.Trigger.Props) {
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
}
function TooltipContent({
className,
side = "bottom",
sideOffset = 10,
align = "center",
alignOffset = 0,
size = "sm",
showArrow = true,
children,
...props
}: TooltipPrimitive.Popup.Props &
Pick<
TooltipPrimitive.Positioner.Props,
"align" | "alignOffset" | "side" | "sideOffset"
> & {
size?: "sm" | "default";
showArrow?: boolean;
}) {
return (
<TooltipPrimitive.Portal>
<TooltipPrimitive.Positioner
align={align}
alignOffset={alignOffset}
side={side}
sideOffset={sideOffset}
className="isolate z-50"
>
<TooltipPrimitive.Popup
data-slot="tooltip-content"
className={cn(
"pointer-events-none z-50 inline-flex max-w-[240px] items-center gap-1.5 origin-(--transform-origin) rounded-[8px] border border-border bg-popover font-medium text-popover-foreground select-none shadow-[shadow:var(--shadow-dropdown,0_1px_1px_0_rgb(0_0_0/0.04),0_4px_4px_0_rgb(0_0_0/0.02))] transition-[scale,opacity,filter] duration-200 ease-out data-[instant]:transition-none data-starting-style:scale-90 data-starting-style:opacity-0 data-starting-style:blur-[4px] data-ending-style:scale-90 data-ending-style:opacity-0 data-ending-style:blur-[4px] motion-reduce:transition-none motion-reduce:data-starting-style:scale-100 motion-reduce:data-starting-style:opacity-100 motion-reduce:data-starting-style:blur-none motion-reduce:data-ending-style:scale-100 motion-reduce:data-ending-style:opacity-100 motion-reduce:data-ending-style:blur-none",
size === "sm"
? "px-2.5 py-1.5 text-xs leading-4 tracking-[0.15px]"
: "rounded-[10px] px-3 py-2 text-sm leading-5 tracking-normal",
className
)}
{...props}
>
{showArrow && (
<TooltipPrimitive.Arrow className="data-[side=top]:-bottom-[6px] data-[side=bottom]:-top-[6px] data-[side=left]:-right-[6px] data-[side=right]:-left-[6px]">
{(
[
["top", 12, 7, "M0 0 L6 6 L12 0"],
["bottom", 12, 7, "M0 7 L6 1 L12 7"],
["left", 7, 12, "M0 0 L6 6 L0 12"],
["right", 7, 12, "M7 0 L1 6 L7 12"],
] as const
).map(([direction, width, height, path]) => (
<svg
key={direction}
width={width}
height={height}
viewBox={`0 0 ${width} ${height}`}
className={cn(
"hidden overflow-visible fill-popover stroke-border [[data-side=top]>&]:[filter:drop-shadow(0_1.5px_1px_rgb(0_0_0/0.05))] [[data-side=bottom]>&]:[filter:drop-shadow(0_-1.5px_1px_rgb(0_0_0/0.05))] [[data-side=left]>&]:[filter:drop-shadow(0_1.5px_1px_rgb(0_0_0/0.05))] [[data-side=right]>&]:[filter:drop-shadow(0_1.5px_1px_rgb(0_0_0/0.05))]",
direction === "top" && "[[data-side=top]>&]:block",
direction === "bottom" && "[[data-side=bottom]>&]:block",
direction === "left" && "[[data-side=left]>&]:block",
direction === "right" && "[[data-side=right]>&]:block"
)}
aria-hidden="true"
>
<path d={path} />
</svg>
))}
</TooltipPrimitive.Arrow>
)}
{children}
</TooltipPrimitive.Popup>
</TooltipPrimitive.Positioner>
</TooltipPrimitive.Portal>
);
}
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; On this page