# Tooltip

A hover and focus label built on Radix Tooltip, with a provider for shared open and close delays, configurable placement, collision handling, and an offset.

- Category: Overlays & Navigation
- License: MIT
- Page: https://www.saasuji.com/components/tooltip
- Install: npx shadcn@latest add https://www.saasuji.com/r/tooltip.json

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| delayDuration (TooltipProvider) | `number` | `700` | Time in milliseconds a pointer must rest on a trigger before the tooltip opens. |
| skipDelayDuration (TooltipProvider) | `number` | `300` | Window in milliseconds during which moving between triggers skips the open delay. |
| disableHoverableContent (TooltipProvider, Tooltip) | `boolean` | `false` | Prevents the tooltip from staying open while the pointer moves over its content. |
| open (Tooltip) | `boolean` | — | Controlled open state of the tooltip. |
| defaultOpen (Tooltip) | `boolean` | `false` | Open state on first render for an uncontrolled tooltip. |
| onOpenChange (Tooltip) | `(open: boolean) => void` | — | Called when the open state changes. |
| delayDuration (Tooltip) | `number` | `700` | Per-tooltip open delay that overrides the provider value. |
| asChild (TooltipTrigger) | `boolean` | `false` | Renders the trigger as its child element instead of the default button. |
| side (TooltipContent) | `"top" | "right" | "bottom" | "left"` | `"top"` | Preferred side of the trigger the tooltip is placed against. |
| sideOffset (TooltipContent) | `number` | `4` | Distance in pixels between the trigger and the tooltip. |
| align (TooltipContent) | `"start" | "center" | "end"` | `"center"` | Alignment of the tooltip along the trigger edge. |
| alignOffset (TooltipContent) | `number` | `0` | Pixel offset applied along the alignment axis. |
| avoidCollisions (TooltipContent) | `boolean` | `true` | Shifts and flips the tooltip to stay inside the viewport. |
| className (TooltipContent) | `string` | — | Additional classes merged onto the tooltip content. |
| children (TooltipProvider, Tooltip, TooltipTrigger, TooltipContent) | `React.ReactNode` | — | Tooltip wraps the trigger and content; TooltipProvider must wrap the whole tree, and the content holds the label. |
| ...props (TooltipProvider) | `React.ComponentProps<typeof TooltipPrimitive.Provider>` | — | All remaining Radix provider props are forwarded. |
| ...props (Tooltip) | `React.ComponentProps<typeof TooltipPrimitive.Root>` | — | All remaining Radix Tooltip root props are forwarded. |
| ...props (TooltipTrigger, TooltipContent) | `React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger> | React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>` | — | All remaining Radix trigger and content props are forwarded (onEscapeKeyDown, collisionBoundary, …). |

## Source

```tsx
"use client"

import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"

import { cn } from "@/lib/utils"

const TooltipProvider = TooltipPrimitive.Provider

const Tooltip = TooltipPrimitive.Root

const TooltipTrigger = TooltipPrimitive.Trigger

const TooltipContent = React.forwardRef<
    React.ElementRef<typeof TooltipPrimitive.Content>,
    React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
    <TooltipPrimitive.Content
        ref={ref}
        sideOffset={sideOffset}
        className={cn(
            "z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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",
            className
        )}
        {...props}
    />
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName

export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }

```
