# Tooltip
URL: /design/components/tooltip

A short label that appears on hover and stays out of the way.

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

\[interactive preview component TooltipSpecimen omitted]

Code for TooltipSpecimen preview:

```tsx
"use client";

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

function TooltipSpecimen(): ReactNode {
  return (
    <Tooltip>
      <TooltipTrigger render={<Button variant="outline">Hover me</Button>} />
      <TooltipContent>Copy message</TooltipContent>
    </Tooltip>
  );
}
```

## Installation

Install the dependencies:

- packages

  - @base-ui/react

Copy the source into `components/ui/tooltip.tsx`. Registry items that depend on it install it automatically.

- code

  "use client"; import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"; import { cn } from "@/lib/utils"; 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 = "top", sideOffset = 4, align = "center", alignOffset = 0, children, ...props }: TooltipPrimitive.Popup.Props & Pick< TooltipPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" >) { 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( "bg-foreground text-background data-\[side=bottom]:slide-in-from-top-2 data-\[side=inline-end]:slide-in-from-left-2 data-\[side=inline-start]:slide-in-from-right-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=delayed-open]:animate-in data-\[state=delayed-open]:fade-in-0 data-\[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-\[var(--radius-surface,var(--radius-lg))] px-3 py-1.5 text-xs has-data-\[slot=kbd]:pr-1.5 \*\*:data-\[slot=kbd]:relative \*\*:data-\[slot=kbd]:isolate \*\*:data-\[slot=kbd]:z-50 \*\*:data-\[slot=kbd]:rounded-sm", className, )} {...props} > {children} \<TooltipPrimitive.Arrow data-slot="tooltip-arrow" className="bg-foreground fill-foreground z-50 size-2.5 translate-y-\[calc(-50%-2px)] rotate-45 rounded-\[2px] data-\[side=bottom]:top-1 data-\[side=inline-end]:top-1/2! data-\[side=inline-end]:-left-1 data-\[side=inline-end]:-translate-y-1/2 data-\[side=inline-start]:top-1/2! data-\[side=inline-start]:-right-1 data-\[side=inline-start]:-translate-y-1/2 data-\[side=left]:top-1/2! data-\[side=left]:-right-1 data-\[side=left]:-translate-y-1/2 data-\[side=right]:top-1/2! data-\[side=right]:-left-1 data-\[side=right]:-translate-y-1/2 data-\[side=top]:-bottom-2.5" /> \</TooltipPrimitive.Popup> \</TooltipPrimitive.Positioner> \</TooltipPrimitive.Portal> ); } export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

* title

  components/ui/tooltip.tsx

* copyText

  "use client"; import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"; import { cn } from "@/lib/utils"; 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 = "top", sideOffset = 4, align = "center", alignOffset = 0, children, ...props }: TooltipPrimitive.Popup.Props & Pick< TooltipPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" >) { 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( "bg-foreground text-background data-\[side=bottom]:slide-in-from-top-2 data-\[side=inline-end]:slide-in-from-left-2 data-\[side=inline-start]:slide-in-from-right-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=delayed-open]:animate-in data-\[state=delayed-open]:fade-in-0 data-\[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-\[var(--radius-surface,var(--radius-lg))] px-3 py-1.5 text-xs has-data-\[slot=kbd]:pr-1.5 \*\*:data-\[slot=kbd]:relative \*\*:data-\[slot=kbd]:isolate \*\*:data-\[slot=kbd]:z-50 \*\*:data-\[slot=kbd]:rounded-sm", className, )} {...props} > {children} \<TooltipPrimitive.Arrow data-slot="tooltip-arrow" className="bg-foreground fill-foreground z-50 size-2.5 translate-y-\[calc(-50%-2px)] rotate-45 rounded-\[2px] data-\[side=bottom]:top-1 data-\[side=inline-end]:top-1/2! data-\[side=inline-end]:-left-1 data-\[side=inline-end]:-translate-y-1/2 data-\[side=inline-start]:top-1/2! data-\[side=inline-start]:-right-1 data-\[side=inline-start]:-translate-y-1/2 data-\[side=left]:top-1/2! data-\[side=left]:-right-1 data-\[side=left]:-translate-y-1/2 data-\[side=right]:top-1/2! data-\[side=right]:-left-1 data-\[side=right]:-translate-y-1/2 data-\[side=top]:-bottom-2.5" /> \</TooltipPrimitive.Popup> \</TooltipPrimitive.Positioner> \</TooltipPrimitive.Portal> ); } export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

* viewportClassName

  max-h-\[450px]

- language

  tsx

- code

  "use client"; import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"; import { cn } from "@/lib/utils"; 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 = "top", sideOffset = 4, align = "center", alignOffset = 0, children, ...props }: TooltipPrimitive.Popup.Props & Pick< TooltipPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" >) { 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( "bg-foreground text-background data-\[side=bottom]:slide-in-from-top-2 data-\[side=inline-end]:slide-in-from-left-2 data-\[side=inline-start]:slide-in-from-right-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=delayed-open]:animate-in data-\[state=delayed-open]:fade-in-0 data-\[state=delayed-open]:zoom-in-95 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 z-50 inline-flex w-fit max-w-xs origin-(--transform-origin) items-center gap-1.5 rounded-\[var(--radius-surface,var(--radius-lg))] px-3 py-1.5 text-xs has-data-\[slot=kbd]:pr-1.5 \*\*:data-\[slot=kbd]:relative \*\*:data-\[slot=kbd]:isolate \*\*:data-\[slot=kbd]:z-50 \*\*:data-\[slot=kbd]:rounded-sm", className, )} {...props} > {children} \<TooltipPrimitive.Arrow data-slot="tooltip-arrow" className="bg-foreground fill-foreground z-50 size-2.5 translate-y-\[calc(-50%-2px)] rotate-45 rounded-\[2px] data-\[side=bottom]:top-1 data-\[side=inline-end]:top-1/2! data-\[side=inline-end]:-left-1 data-\[side=inline-end]:-translate-y-1/2 data-\[side=inline-start]:top-1/2! data-\[side=inline-start]:-right-1 data-\[side=inline-start]:-translate-y-1/2 data-\[side=left]:top-1/2! data-\[side=left]:-right-1 data-\[side=left]:-translate-y-1/2 data-\[side=right]:top-1/2! data-\[side=right]:-left-1 data-\[side=right]:-translate-y-1/2 data-\[side=top]:-bottom-2.5" /> \</TooltipPrimitive.Popup> \</TooltipPrimitive.Positioner> \</TooltipPrimitive.Portal> ); } export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

## Usage

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

export function Example() {
  return (
    <Tooltip>
      <TooltipTrigger render={<Button variant="outline">Hover me</Button>} />
      <TooltipContent>Copy message</TooltipContent>
    </Tooltip>
  );
}
```

## Examples

### Icon buttons

A tooltip earns its place when the control is an icon alone; written labels do not need one.

\[interactive preview component TooltipIconSpecimen omitted]

Code for TooltipIconSpecimen preview:

```tsx
"use client";

import { useState, type ReactNode } from "react";
import {
  ChevronDownIcon,
  ChevronsUpDownIcon,
  CopyIcon,
  LogOutIcon,
  PlusIcon,
  RefreshCwIcon,
  SettingsIcon,
  UserIcon,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip";

function TooltipIconSpecimen(): ReactNode {
  return (
    <Tooltip>
      <TooltipTrigger
        render={
          <Button size="icon" variant="ghost" aria-label="Copy message">
            <CopyIcon className="size-4" />
          </Button>
        }
      />
      <TooltipContent>Copy message</TooltipContent>
    </Tooltip>
    <Tooltip>
      <TooltipTrigger
        render={
          <Button size="icon" variant="ghost" aria-label="Regenerate">
            <RefreshCwIcon className="size-4" />
          </Button>
        }
      />
      <TooltipContent>Regenerate</TooltipContent>
    </Tooltip>
  );
}
```

## API Reference

The parts wrap Base UI's Tooltip primitives and accept their props.

### TooltipContent

- `side`: `"top" | "right" | "bottom" | "left"` (default `"top"`) — Preferred side of the trigger.
- `sideOffset`: `number` (default `4`) — Distance from the trigger in pixels.

### TooltipProvider

Wrap a region to share hover delay across its tooltips.

- `delay?`: `number` — Milliseconds before the tooltip opens.