Skip to main content
A tooltip is a small popup that displays brief, supplementary information when hovering over or focusing on an element. It’s useful for providing context or explanations without cluttering the interface.

Installation

npx shadcn@latest add @eo-n/tooltip

Usage

Wrap your application with the TooltipProvider to enable tooltips:
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
<TooltipProvider>
  <Tooltip>
    <TooltipTrigger>Hover me</TooltipTrigger>
    <TooltipContent>
      <p>Tooltip content</p>
    </TooltipContent>
  </Tooltip>
</TooltipProvider>

Examples

Basic Tooltip

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

export default function TooltipDemo() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger asChild>
          <Button variant="outline">Hover me</Button>
        </TooltipTrigger>
        <TooltipContent>
          <p>This is a tooltip</p>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

With Icon

Use tooltips to provide context for icon buttons:
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";
import { Info } from "lucide-react";

export default function TooltipIcon() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger asChild>
          <Button variant="ghost" size="icon">
            <Info className="h-4 w-4" />
            <span className="sr-only">More information</span>
          </Button>
        </TooltipTrigger>
        <TooltipContent>
          <p>This provides additional information</p>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

Different Positions

Position the tooltip on different sides:
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";

export default function TooltipPositions() {
  return (
    <TooltipProvider>
      <div className="flex gap-4">
        <Tooltip>
          <TooltipTrigger asChild>
            <Button>Top</Button>
          </TooltipTrigger>
          <TooltipContent side="top">
            <p>Tooltip on top</p>
          </TooltipContent>
        </Tooltip>

        <Tooltip>
          <TooltipTrigger asChild>
            <Button>Bottom</Button>
          </TooltipTrigger>
          <TooltipContent side="bottom">
            <p>Tooltip on bottom</p>
          </TooltipContent>
        </Tooltip>

        <Tooltip>
          <TooltipTrigger asChild>
            <Button>Left</Button>
          </TooltipTrigger>
          <TooltipContent side="left">
            <p>Tooltip on left</p>
          </TooltipContent>
        </Tooltip>

        <Tooltip>
          <TooltipTrigger asChild>
            <Button>Right</Button>
          </TooltipTrigger>
          <TooltipContent side="right">
            <p>Tooltip on right</p>
          </TooltipContent>
        </Tooltip>
      </div>
    </TooltipProvider>
  );
}

With Delay

Control the delay before the tooltip appears:
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";

export default function TooltipDelay() {
  return (
    <div className="space-y-4">
      <TooltipProvider delay={0}>
        <Tooltip>
          <TooltipTrigger asChild>
            <Button>No delay</Button>
          </TooltipTrigger>
          <TooltipContent>
            <p>Appears immediately</p>
          </TooltipContent>
        </Tooltip>
      </TooltipProvider>

      <TooltipProvider delay={500}>
        <Tooltip>
          <TooltipTrigger asChild>
            <Button>500ms delay</Button>
          </TooltipTrigger>
          <TooltipContent>
            <p>Appears after 500ms</p>
          </TooltipContent>
        </Tooltip>
      </TooltipProvider>

      <TooltipProvider delay={1000}>
        <Tooltip>
          <TooltipTrigger asChild>
            <Button>1s delay</Button>
          </TooltipTrigger>
          <TooltipContent>
            <p>Appears after 1 second</p>
          </TooltipContent>
        </Tooltip>
      </TooltipProvider>
    </div>
  );
}

Rich Content

Tooltips can contain rich content:
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";

export default function TooltipRichContent() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger asChild>
          <Button variant="outline">View details</Button>
        </TooltipTrigger>
        <TooltipContent className="max-w-xs">
          <div className="space-y-2">
            <p className="font-semibold">Product Information</p>
            <p className="text-xs">
              This product includes advanced features and premium support.
            </p>
          </div>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

Multiple Tooltips

Share a TooltipProvider across multiple tooltips:
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";
import { Button } from "@/components/ui/button";

export default function MultipleTooltips() {
  return (
    <TooltipProvider>
      <div className="flex gap-4">
        <Tooltip>
          <TooltipTrigger asChild>
            <Button>Save</Button>
          </TooltipTrigger>
          <TooltipContent>
            <p>Save your changes</p>
          </TooltipContent>
        </Tooltip>

        <Tooltip>
          <TooltipTrigger asChild>
            <Button variant="outline">Cancel</Button>
          </TooltipTrigger>
          <TooltipContent>
            <p>Discard changes</p>
          </TooltipContent>
        </Tooltip>

        <Tooltip>
          <TooltipTrigger asChild>
            <Button variant="destructive">Delete</Button>
          </TooltipTrigger>
          <TooltipContent>
            <p>Permanently delete</p>
          </TooltipContent>
        </Tooltip>
      </div>
    </TooltipProvider>
  );
}

API Reference

TooltipProvider

Wrapper component that provides tooltip context. Should wrap all tooltips in your app.
delay
number
default:"0"
The delay in milliseconds before the tooltip appears.
skipDelayDuration
number
default:"300"
How long a user has to enter another tooltip before the delay is ignored.

Tooltip

The root component that manages the tooltip state.
open
boolean
Controls the open state of the tooltip.
defaultOpen
boolean
The initial open state for uncontrolled usage.
onOpenChange
(open: boolean) => void
Callback fired when the open state changes.

TooltipTrigger

The element that triggers the tooltip.
asChild
boolean
default:"false"
Merge props onto the child element instead of wrapping it.

TooltipContent

The content to be rendered in the tooltip.
side
'top' | 'right' | 'bottom' | 'left'
default:"'top'"
The preferred side of the trigger to render against when open.
sideOffset
number
default:"10"
The distance in pixels from the trigger.
align
'start' | 'center' | 'end'
default:"'center'"
The preferred alignment against the trigger.
alignOffset
number
default:"0"
An offset in pixels from the alignment.
className
string
Additional CSS classes to apply.

TooltipCreateHandle

Creates a handle for imperative tooltip control.
const handleRef = TooltipCreateHandle();

// Later, use the handle to control the tooltip
handleRef.current?.open();
handleRef.current?.close();

Accessibility

  • Tooltips are keyboard accessible and work with screen readers
  • The tooltip content is associated with the trigger via aria-describedby
  • Pressing Escape will close an open tooltip
  • Tooltips automatically position themselves to stay within the viewport

Build docs developers (and LLMs) love