Getting Started
Components
- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
Demos
A tooltip that names an icon button.
"use client"
import { DownloadIcon } from "lucide-react"
import { Button } from "@workspace/ui/components/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@workspace/ui/components/tooltip"
export function TooltipDemo() {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger
render={<Button variant="outline" size="icon" aria-label="Download report" />}
>
<DownloadIcon />
</TooltipTrigger>
<TooltipContent>Download report</TooltipContent>
</Tooltip>
</TooltipProvider>
)
}
Usage
Use a tooltip to name an icon button or add a brief hint. Keep it to a few words. Never put information the reader needs only in a tooltip. Touch screens have no hover. For longer content or links, use a Popover.
Import it from @workspace/ui/components/tooltip.
Anatomy
- TooltipProvider — Sets the delay and groups tooltips. Wrap your app once. Without it, a tooltip waits 600 ms before it opens.
- Tooltip — Holds the open state.
- TooltipTrigger — The element that shows the tooltip. Pass a button through
render. - TooltipContent — The label and its arrow.
Notes
- The tooltip opens on hover and on keyboard focus.
- An icon button still needs its own
aria-label. The tooltip does not name it.
Examples
Sides
Set side on TooltipContent to open on any side of the trigger.
"use client"
import { Button } from "@workspace/ui/components/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@workspace/ui/components/tooltip"
const sides = ["top", "right", "bottom", "left"] as const
export function TooltipSides() {
return (
<TooltipProvider>
<div className="flex flex-wrap items-center justify-center gap-3">
{sides.map((side) => (
<Tooltip key={side}>
<TooltipTrigger render={<Button variant="outline" className="capitalize" />}>
{side}
</TooltipTrigger>
<TooltipContent side={side}>Opens on the {side}</TooltipContent>
</Tooltip>
))}
</div>
</TooltipProvider>
)
}
Toolbar
One TooltipProvider around a group shares the delay. Once one tooltip is open, the next opens right away.
"use client"
import { DownloadIcon, PrinterIcon, ShareIcon } from "lucide-react"
import { Button } from "@workspace/ui/components/button"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@workspace/ui/components/tooltip"
const actions = [
{ label: "Download report", icon: DownloadIcon },
{ label: "Share with doctor", icon: ShareIcon },
{ label: "Print", icon: PrinterIcon },
]
export function TooltipToolbar() {
return (
<TooltipProvider delay={300}>
<div className="flex items-center gap-1 rounded-full border p-1">
{actions.map((action) => (
<Tooltip key={action.label}>
<TooltipTrigger
render={<Button variant="ghost" size="icon-sm" aria-label={action.label} />}
>
<action.icon />
</TooltipTrigger>
<TooltipContent>{action.label}</TooltipContent>
</Tooltip>
))}
</div>
</TooltipProvider>
)
}
Props
These are the props you set most often. Unlisted props pass through to the underlying element.
TooltipProvider
| Prop | Type | Default | Description |
|---|---|---|---|
delay | number | 0 | Milliseconds before a tooltip opens. |
closeDelay | number | 0 | Milliseconds before a tooltip closes. |
TooltipContent
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top", "right", "bottom", "left", "inline-start", or "inline-end" | top | Side of the trigger to open on. |
align | "start", "center", or "end" | center | Alignment along that side. |
sideOffset | number | 4 | Gap from the trigger in pixels. |
alignOffset | number | 0 | Shift along the side in pixels. |
className | string | — | Classes merged onto the label. |