Github

Tooltip

A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.

"use client";

import { Button } from "@/components/ui/button";
import {
	Tooltip,
	TooltipContent,
	TooltipTrigger,
} from "@/components/ui/tooltip";

export function TooltipDemo() {
	return (
		<Tooltip>
			<TooltipTrigger render={<Button variant="tertiary" />}>
				Hover
			</TooltipTrigger>
			<TooltipContent>
				<p>Add to library</p>
			</TooltipContent>
		</Tooltip>
	);
}

Installation

Run the following command:

pnpm dlx shadcn@latest add https://herocn.dev/r/tooltip.json

Add the TooltipProvider to the root of your app.

app/layout.tsx
import { TooltipProvider } from "@/components/ui/tooltip"

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode
}>) {
  return (
    <html lang="en">
      <body>
        <TooltipProvider>{children}</TooltipProvider>
      </body>
    </html>
  )
}

Usage

import { Button } from "@/components/ui/button"
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip"
<Tooltip>
  <TooltipTrigger render={<Button variant="outline" />}>Hover</TooltipTrigger>
  <TooltipContent>
    <p>Add to library</p>
  </TooltipContent>
</Tooltip>

Composition

Use the following composition to build a Tooltip:

Tooltip
├── TooltipTrigger
└── TooltipContent

Examples

Side

Use the side prop to change the position of the tooltip.

"use client";

import { Button } from "@/components/ui/button";
import {
	Tooltip,
	TooltipContent,
	TooltipTrigger,
} from "@/components/ui/tooltip";

export function TooltipSides() {
	return (
		<div className="flex flex-wrap gap-2">
			{(["left", "top", "bottom", "right"] as const).map((side) => (
				<Tooltip key={side}>
					<TooltipTrigger
						render={<Button variant="tertiary" className="w-fit capitalize" />}
					>
						{side}
					</TooltipTrigger>
					<TooltipContent side={side}>
						<p>Add to library</p>
					</TooltipContent>
				</Tooltip>
			))}
		</div>
	);
}

Arrow

Use the withArrow prop to add arrow to the tooltip

"use client";

import { Button } from "@/components/ui/button";
import {
	Tooltip,
	TooltipContent,
	TooltipTrigger,
} from "@/components/ui/tooltip";

export function ToolTipArrow() {
	return (
		<div className="flex flex-wrap gap-2">
			{(["left", "top", "bottom", "right"] as const).map((side) => (
				<Tooltip key={side}>
					<TooltipTrigger
						render={<Button variant="tertiary" className="w-fit capitalize" />}
					>
						{side}
					</TooltipTrigger>
					<TooltipContent withArrow side={side}>
						<p>This tooltip has an arrow</p>
					</TooltipContent>
				</Tooltip>
			))}
		</div>
	);
}

With keyboard shortcut

"use client";

import { SaveIcon } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Kbd } from "@/components/ui/kbd";
import {
	Tooltip,
	TooltipContent,
	TooltipTrigger,
} from "@/components/ui/tooltip";

export function TooltipKeyboard() {
	return (
		<Tooltip>
			<TooltipTrigger render={<Button variant="tertiary" size="icon-sm" />}>
				<SaveIcon />
			</TooltipTrigger>
			<TooltipContent>
				Save Changes <Kbd>S</Kbd>
			</TooltipContent>
		</Tooltip>
	);
}

Disabled button

Show a tooltip on a disabled button by wrapping it with a span.

"use client";

import { Button } from "@/components/ui/button";
import {
	Tooltip,
	TooltipContent,
	TooltipTrigger,
} from "@/components/ui/tooltip";

export function TooltipDisabled() {
	return (
		<Tooltip>
			<TooltipTrigger render={<span className="inline-block w-fit" />}>
				<Button variant="tertiary" disabled>
					Disabled
				</Button>
			</TooltipTrigger>
			<TooltipContent>
				<p>This feature is currently unavailable</p>
			</TooltipContent>
		</Tooltip>
	);
}

RTL

To enable RTL support in shadcn/ui, see the RTL configuration guide.

"use client";

import {
	type Translations,
	useTranslation,
} from "@/components/language-selector";
import { Button } from "@/components/ui/button";
import {
	Tooltip,
	TooltipContent,
	TooltipTrigger,
} from "@/components/ui/tooltip";

const translations: Translations = {
	en: {
		dir: "ltr",
		values: {
			content: "Add to library",
			"inline-start": "Inline Start",
			left: "Left",
			top: "Top",
			bottom: "Bottom",
			right: "Right",
			"inline-end": "Inline End",
		},
	},
	ar: {
		dir: "rtl",
		values: {
			content: "إضافة إلى المكتبة",
			"inline-start": "بداية السطر",
			left: "يسار",
			top: "أعلى",
			bottom: "أسفل",
			right: "يمين",
			"inline-end": "نهاية السطر",
		},
	},
	he: {
		dir: "rtl",
		values: {
			content: "הוסף לספרייה",
			"inline-start": "תחילת השורה",
			left: "שמאל",
			top: "למעלה",
			bottom: "למטה",
			right: "ימין",
			"inline-end": "סוף השורה",
		},
	},
};

const physicalSides = ["left", "top", "bottom", "right"] as const;
const logicalSides = ["inline-start", "inline-end"] as const;

export function TooltipRtl() {
	const { dir, language, t } = useTranslation(translations, "ar");

	return (
		<div lang={language} dir={dir} className="grid gap-4">
			<div className="flex flex-wrap justify-center gap-2">
				{physicalSides.map((side) => (
					<Tooltip key={side}>
						<TooltipTrigger render={<Button variant="tertiary" />}>
							{t[side]}
						</TooltipTrigger>
						<TooltipContent side={side} dir={dir}>
							{t.content}
						</TooltipContent>
					</Tooltip>
				))}
			</div>
			<div className="flex flex-wrap justify-center gap-2">
				{logicalSides.map((side) => (
					<Tooltip key={side}>
						<TooltipTrigger render={<Button variant="tertiary" />}>
							{t[side]}
						</TooltipTrigger>
						<TooltipContent side={side} dir={dir}>
							{t.content}
						</TooltipContent>
					</Tooltip>
				))}
			</div>
		</div>
	);
}

API Reference

The tooltip is built on Base UI Tooltip. TooltipContent sets default positioning and passes the remaining props to the popup.

TooltipContent

PropTypeDefault

TooltipProvider

PropTypeDefault

See the Base UI Tooltip API reference for root, trigger, and other props.