- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Dialog
- EmptyNew
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input GroupNew
- KbdNew
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- SkeletonNew
- Slider
- SpinnerNew
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
Tooltip
A popup that appears when an element is hovered or focused, showing a hint for sighted users.
import { Button } from "@/components/ui/button";
import {
Tooltip,
TooltipPopup,
TooltipTrigger,
} from "@/components/ui/tooltip";
export default function Particle() {
return (
<Tooltip>
<TooltipTrigger render={<Button variant="outline" />}>
Hover me
</TooltipTrigger>
<TooltipPopup>Helpful hint</TooltipPopup>
</Tooltip>
);
}
Installation
pnpm dlx shadcn@latest add @coss/tooltip
Usage
import {
Tooltip,
TooltipCreateHandle,
TooltipPopup,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"<Tooltip>
<TooltipTrigger render={<Button variant="outline" />}>
Hover me
</TooltipTrigger>
<TooltipPopup>Helpful hint</TooltipPopup>
</Tooltip>Examples
Grouped Tooltips
To group multiple tooltips so they appear instantly after the first one is opened, wrap them in TooltipProvider. The grouping logic ensures that once a tooltip becomes visible, the adjacent tooltips will be shown instantly.
import { BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react";
import { Toggle, ToggleGroup } from "@/components/ui/toggle-group";
import {
Tooltip,
TooltipPopup,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
export default function Particle() {
return (
<TooltipProvider>
<ToggleGroup defaultValue={["bold"]} multiple>
<Tooltip>
<TooltipTrigger
render={<Toggle aria-label="Toggle bold" value="bold" />}
>
<BoldIcon />
</TooltipTrigger>
<TooltipPopup>Bold</TooltipPopup>
</Tooltip>
<Tooltip>
<TooltipTrigger
render={<Toggle aria-label="Toggle italic" value="italic" />}
>
<ItalicIcon />
</TooltipTrigger>
<TooltipPopup>Italic</TooltipPopup>
</Tooltip>
<Tooltip>
<TooltipTrigger
render={<Toggle aria-label="Toggle underline" value="underline" />}
>
<UnderlineIcon />
</TooltipTrigger>
<TooltipPopup>Underline</TooltipPopup>
</Tooltip>
</ToggleGroup>
</TooltipProvider>
);
}
Animated Tooltips
You can create animated tooltips that smoothly transition between different triggers using detached triggers. This pattern allows multiple triggers to share a single tooltip popup, with automatic animations for position, size, and content changes.
To create detached triggers:
- Create a handle using
TooltipCreateHandle - Attach the same handle to multiple
TooltipTriggercomponents - Each trigger provides a
payloadprop containing the content component - Use a single
Tooltipcomponent with the handle to render the popup
"use client";
import { BoldIcon, ItalicIcon, UnderlineIcon } from "lucide-react";
import { Toggle, ToggleGroup } from "@/components/ui/toggle-group";
import {
Tooltip,
TooltipCreateHandle,
TooltipPopup,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
const tooltipHandle = TooltipCreateHandle<React.ComponentType>();
const BoldContent = () => {
return <span>Make text bold</span>;
};
const ItalicContent = () => {
return <span>Apply italic formatting to text</span>;
};
const UnderlineContent = () => {
return <span>Underline text</span>;
};
export default function Particle() {
return (
<TooltipProvider>
<ToggleGroup defaultValue={["bold"]} multiple>
<TooltipTrigger
className="after:absolute after:left-full after:h-full after:w-1"
handle={tooltipHandle}
payload={BoldContent}
render={<Toggle aria-label="Toggle bold" value="bold" />}
>
<BoldIcon />
</TooltipTrigger>
<TooltipTrigger
className="after:absolute after:left-full after:h-full after:w-1"
handle={tooltipHandle}
payload={ItalicContent}
render={<Toggle aria-label="Toggle italic" value="italic" />}
>
<ItalicIcon />
</TooltipTrigger>
<TooltipTrigger
className="after:absolute after:left-full after:h-full after:w-1"
handle={tooltipHandle}
payload={UnderlineContent}
render={<Toggle aria-label="Toggle underline" value="underline" />}
>
<UnderlineIcon />
</TooltipTrigger>
</ToggleGroup>
<Tooltip handle={tooltipHandle}>
{({ payload: Payload }) => (
<TooltipPopup>{Payload !== undefined && <Payload />}</TooltipPopup>
)}
</Tooltip>
</TooltipProvider>
);
}
Comparing with Radix / shadcn
If you’re already familiar with Radix UI and shadcn/ui, this guide highlights the small differences and similarities so you can get started with coss ui quickly.
Quick Checklist
- Replace
asChild→renderonTooltipTrigger - Prefer
TooltipPopup;TooltipContentremains for legacy - If you used
asChildon parts, switch to therenderprop
Comparison Example
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover me</Button>
</TooltipTrigger>
<TooltipContent>Helpful hint</TooltipContent>
</Tooltip><Tooltip>
<TooltipTrigger render={<Button variant="outline" />}>
Hover me
</TooltipTrigger>
<TooltipPopup>Helpful hint</TooltipPopup>
</Tooltip>