Documentation Index
Fetch the complete documentation index at: https://mintlify.com/shadcn-ui/ui/llms.txt
Use this file to discover all available pages before exploring further.
Installation
npx shadcn@latest add tooltip
Setup
Add the TooltipProvider to the root of your app:
import { TooltipProvider } from "@/components/ui/tooltip"
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<TooltipProvider>{children}</TooltipProvider>
</body>
</html>
)
}
Usage
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
<Tooltip>
<TooltipTrigger>Hover</TooltipTrigger>
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
Examples
Basic
A simple tooltip with text content.
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
export default function TooltipDemo() {
return (
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover</Button>
</TooltipTrigger>
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
)
}
Positioning
Control the position of the tooltip using the side prop.
With Arrow
Tooltips include an arrow by default pointing to the trigger element.
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
export default function TooltipWithArrow() {
return (
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover me</Button>
</TooltipTrigger>
<TooltipContent>
<p>This tooltip has an arrow</p>
</TooltipContent>
</Tooltip>
)
}
Keyboard Shortcut
Display keyboard shortcuts in tooltips.
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
export default function TooltipKeyboard() {
return (
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Save</Button>
</TooltipTrigger>
<TooltipContent>
<p className="flex items-center gap-2">
Save changes
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
<span className="text-xs">⌘</span>S
</kbd>
</p>
</TooltipContent>
</Tooltip>
)
}
Disabled Button
Show a tooltip on a disabled button by wrapping it with a span.
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
export default function TooltipDisabled() {
return (
<Tooltip>
<TooltipTrigger asChild>
<span className="inline-block">
<Button disabled>Disabled</Button>
</span>
</TooltipTrigger>
<TooltipContent>
<p>This action is currently disabled</p>
</TooltipContent>
</Tooltip>
)
}
Delay Duration
Control how long the user must hover before the tooltip appears.
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
export default function TooltipDelay() {
return (
<Tooltip delayDuration={0}>
<TooltipTrigger asChild>
<Button variant="outline">Instant</Button>
</TooltipTrigger>
<TooltipContent>
<p>This tooltip appears instantly</p>
</TooltipContent>
</Tooltip>
)
}
Rich Content
Tooltips can contain rich content, not just text.
import { Button } from "@/components/ui/button"
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
export default function TooltipRichContent() {
return (
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">Hover for details</Button>
</TooltipTrigger>
<TooltipContent className="max-w-xs">
<div className="space-y-2">
<p className="font-semibold">Feature Details</p>
<p className="text-xs text-muted-foreground">
This feature allows you to customize the appearance and behavior of
your components.
</p>
</div>
</TooltipContent>
</Tooltip>
)
}
Component Code
"use client"
import * as React from "react"
import { Tooltip as TooltipPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
function TooltipProvider({
delayDuration = 0,
...props
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
return (
<TooltipPrimitive.Provider
data-slot="tooltip-provider"
delayDuration={delayDuration}
{...props}
/>
)
}
function Tooltip({
...props
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />
}
function TooltipTrigger({
...props
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
}
function TooltipContent({
className,
sideOffset = 0,
children,
...props
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
return (
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
data-slot="tooltip-content"
sideOffset={sideOffset}
className={cn(
"z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
className
)}
{...props}
>
{children}
<TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-foreground fill-foreground" />
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal>
)
}
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
Props
TooltipProvider
| Prop | Type | Default | Description |
|---|
delayDuration | number | 0 | Time in ms before tooltip appears |
skipDelayDuration | number | 300 | Time before delay resets after pointer leaves |
disableHoverableContent | boolean | false | Prevents hovering over tooltip content |
Tooltip
| Prop | Type | Default | Description |
|---|
open | boolean | - | Controlled open state |
defaultOpen | boolean | false | Default open state (uncontrolled) |
onOpenChange | (open: boolean) => void | - | Callback when open state changes |
delayDuration | number | - | Overrides provider’s delayDuration |
TooltipTrigger
| Prop | Type | Default | Description |
|---|
asChild | boolean | false | Merge props with child element |
className | string | - | Additional CSS classes |
TooltipContent
| Prop | Type | Default | Description |
|---|
side | "top" | "right" | "bottom" | "left" | "top" | Preferred side of the trigger |
sideOffset | number | 0 | Distance from trigger in pixels |
align | "start" | "center" | "end" | "center" | Alignment relative to trigger |
alignOffset | number | 0 | Offset from alignment position |
className | string | - | Additional CSS classes |
Accessibility
- Automatically associates tooltip with trigger using
aria-describedby
- Keyboard accessible (opens on focus, closes on blur/escape)
- Uses
role="tooltip" for screen readers
- Portal rendering prevents z-index issues
- Respects
prefers-reduced-motion
Best Practices
- Keep tooltip text concise and informative
- Don’t use tooltips for critical information
- Ensure tooltips don’t hide important content
- Use
asChild on trigger to merge with custom components
- Wrap disabled buttons in a span to enable tooltips
- Consider using instant tooltips (
delayDuration={0}) for frequently accessed items
API Reference
Built on top of Radix UI Tooltip. See the official API documentation for more details.