# Tooltip

A short text label that appears when the pointer rests on, or focus reaches, a control.

```tsx
import { RefreshCwIcon } from "lucide-react"
import { Button } from "@zenoxai/ui/components/button"
import { Tooltip, TooltipContent, TooltipTrigger } from "@zenoxai/ui/components/tooltip"

function TooltipDemo() {
  return (
    <Tooltip>
      <TooltipTrigger
        render={
          <Button variant="outline" size="icon" aria-label="Refresh alerts" />
        }
      >
        <RefreshCwIcon />
      </TooltipTrigger>
      <TooltipContent>Refresh alerts</TooltipContent>
    </Tooltip>
  )
}
```

## Usage

```tsx
import { RefreshCwIcon } from "lucide-react"

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

```tsx
<Tooltip>
  <TooltipTrigger
    render={
      <Button variant="outline" size="icon" aria-label="Refresh alerts" />
    }
  >
    <RefreshCwIcon />
  </TooltipTrigger>
  <TooltipContent>Refresh alerts</TooltipContent>
</Tooltip>
```

Use a tooltip to name an icon button or to add a few words about a control: the action of an
icon in a toolbar, a keyboard shortcut, the full text of a truncated label. Keep it to one short
line. The user must be able to work without ever seeing it: tooltips do not open on touch
screens.

- For an explanation the user opens on purpose (an info icon next to a figure), use
  [Popover](/components/popover) with `openOnHover`, or the
  [Help Tooltip](/patterns/help-tooltip) pattern for the standard info icon.
- For a preview of a linked record (an asset, a user), use [Hover Card](/components/hover-card).
- For a message after an action ("Copied"), raise a [toast](/components/sonner).

Render the trigger through `render` so the tooltip attaches to the real button. A tooltip on a
disabled button never opens, because a disabled button receives no pointer or focus events;
make it reachable with `focusableWhenDisabled` on the `Button`.

## Examples

### With a keyboard shortcut

Put a `Kbd` after the label. The tooltip restyles it to read on its inverted background: dark in
the light theme, light in the dark theme.

```tsx
import { BellOffIcon } from "lucide-react"
import { Button } from "@zenoxai/ui/components/button"
import { Kbd } from "@zenoxai/ui/components/kbd"
import { Tooltip, TooltipContent, TooltipTrigger } from "@zenoxai/ui/components/tooltip"

function TooltipWithShortcut() {
  return (
    <Tooltip>
      <TooltipTrigger
        render={
          <Button variant="outline" size="icon" aria-label="Mute alert" />
        }
      >
        <BellOffIcon />
      </TooltipTrigger>
      <TooltipContent>
        Mute alert <Kbd>M</Kbd>
      </TooltipContent>
    </Tooltip>
  )
}
```

### Side

`side` is `top` by default; `align` moves it along that side. The tooltip flips when there is
no room.

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

function TooltipSides() {
  return (
    <>
      {(["top", "right", "bottom", "left"] as const).map((side) => (
        <Tooltip key={side}>
          <TooltipTrigger render={<Button variant="outline" />}>
            {side}
          </TooltipTrigger>
          <TooltipContent side={side}>Opens on the {side}</TooltipContent>
        </Tooltip>
      ))}
    </>
  )
}
```

### Group with a provider

A tooltip opens 600ms after the pointer arrives. Inside `TooltipProvider`, tooltips open
without delay, and moving from one trigger to the next swaps them at once, which suits toolbars.
Wrap a toolbar, or the whole app, in one provider; pass `delay` to it to set a different value.

```tsx
import { DownloadIcon, ShareIcon, Trash2Icon } from "lucide-react"
import { Button } from "@zenoxai/ui/components/button"
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@zenoxai/ui/components/tooltip"

function TooltipGroup() {
  return (
    <TooltipProvider>
      <div className="flex gap-1">
        <Tooltip>
          <TooltipTrigger
            render={
              <Button
                variant="ghost"
                size="icon"
                aria-label="Download report"
              />
            }
          >
            <DownloadIcon />
          </TooltipTrigger>
          <TooltipContent>Download report</TooltipContent>
        </Tooltip>
        <Tooltip>
          <TooltipTrigger
            render={
              <Button variant="ghost" size="icon" aria-label="Share report" />
            }
          >
            <ShareIcon />
          </TooltipTrigger>
          <TooltipContent>Share report</TooltipContent>
        </Tooltip>
        <Tooltip>
          <TooltipTrigger
            render={
              <Button variant="ghost" size="icon" aria-label="Delete report" />
            }
          >
            <Trash2Icon />
          </TooltipTrigger>
          <TooltipContent>Delete report</TooltipContent>
        </Tooltip>
      </div>
    </TooltipProvider>
  )
}
```

## Accessibility

- A tooltip is a visual label for pointer and keyboard users. It is not the accessible name of
  its trigger: give every icon-only trigger an `aria-label` with the same words.
- The tooltip opens on hover and on keyboard focus, and closes on Escape, on blur and when the
  trigger is clicked.
- Never put links, buttons or anything the user must read to complete a task inside a tooltip.

## API reference

`import { ... } from "@zenoxai/ui/components/tooltip"`

### Tooltip

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| actionsRef | `RefObject<TooltipRootActions \| null>` |  | A ref to imperative actions. - `unmount`: Ends the closing phase of the tooltip after an externally controlled closing animation finishes. Call `preventUnmountOnClose()` in `onOpenChange` first, otherwise the tooltip completes closing on its own. Whether it leaves the DOM is decided by `keepMounted` on the portal. - `close`: Closes the tooltip imperatively when called. |
| defaultOpen | `boolean` | `false` | Whether the tooltip is initially open.  To render a controlled tooltip, use the `open` prop instead. |
| defaultTriggerId | `string \| null` |  | ID of the trigger that the tooltip is associated with. This is useful in conjunction with the `defaultOpen` prop to create an initially open tooltip. |
| disabled | `boolean` | `false` | Whether the tooltip is disabled. |
| disableHoverablePopup | `boolean` | `false` | Whether the tooltip contents can be hovered without closing the tooltip. |
| handle | `TooltipHandle<unknown>` |  | A handle to associate the tooltip with a trigger. If specified, allows external triggers to control the tooltip's open state. Can be created with the Tooltip.createHandle() method. |
| onOpenChange | `((open: boolean, eventDetails: TooltipRootChangeEventDetails) => void)` |  | Event handler called when the tooltip is opened or closed. |
| onOpenChangeComplete | `((open: boolean) => void)` |  | Event handler called after any animations complete when the tooltip is opened or closed. |
| open | `boolean` |  | Whether the tooltip is currently open. |
| trackCursorAxis | `"none" \| "both" \| "x" \| "y"` | `'none'` | Determines which axis the tooltip should track the cursor on. |
| triggerId | `string \| null` |  | ID of the trigger that the tooltip is associated with. This is useful in conjunction with the `open` prop to create a controlled tooltip. There's no need to specify this prop when the tooltip is uncontrolled (that is, when the `open` prop is not set). |

### TooltipTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| closeDelay | `number` | `0` | How long to wait before closing the tooltip. Specified in milliseconds. |
| closeOnClick | `boolean` | `true` | Whether the tooltip should close when this trigger is clicked. |
| delay | `number` | `600` | How long to wait before opening the tooltip on hover. Specified in milliseconds. |
| disabled | `boolean` | `false` | If `true`, the tooltip will not open when interacting with this trigger. Note that this doesn't apply the `disabled` attribute to the trigger element. If you want to disable the trigger element itself, you can pass the `disabled` prop to the trigger element via the `render` prop. |
| handle | `TooltipHandle<unknown>` |  | A handle to associate the trigger with a tooltip. |
| payload | `unknown` |  | A payload to pass to the tooltip when it is opened. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, TooltipTriggerState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### TooltipContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| align | `"center" \| "start" \| "end"` | `start` | How to align the popup relative to the specified side. |
| alignOffset | `number \| OffsetFunction` | `0` | Additional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment.  The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. @example ```jsx <Positioner   alignOffset={({ side, align, anchor, positioner }) => {     return side === 'top' \|\| side === 'bottom'       ? anchor.width       : anchor.height;   }} /> ``` |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, TooltipPopupState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |
| side | `"left" \| "right" \| "top" \| "bottom" \| "inline-end" \| "inline-start"` | `top` | Which side of the anchor element to align the popup against. May automatically change to avoid collisions. |
| sideOffset | `number \| OffsetFunction` | `0` | Distance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment.  The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. @example ```jsx <Positioner   sideOffset={({ side, align, anchor, positioner }) => {     return side === 'top' \|\| side === 'bottom'       ? anchor.height       : anchor.width;   }} /> ``` |

### TooltipProvider

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| closeDelay | `number` |  | How long to wait before closing a tooltip. Specified in milliseconds. |
| delay | `number` | `0` | How long to wait before opening the tooltip on hover. Specified in milliseconds. |
| timeout | `number` | `400` | Another tooltip will open instantly if the previous tooltip is closed within this timeout. Specified in milliseconds. |

