> ## Documentation Index
> Fetch the complete documentation index at: https://api.fanvue.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Tooltip

> A short label shown on hover or focus, built from TooltipProvider, TooltipTrigger and TooltipContent, with twelve placements.

```tsx theme={null}
import {
  Tooltip,
  TooltipContent,
  TooltipLabel,
  TooltipProvider,
  TooltipTrigger,
} from "@fanvue/ui";
import type {
  TooltipContentProps,
  TooltipLabelProps,
  TooltipPlacement,
  TooltipProps,
  TooltipProviderProps,
  TooltipTriggerProps,
} from "@fanvue/ui";
```

## Examples

## Default

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-tooltip--default&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="240" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Tooltip — Default" />
</Frame>

```tsx theme={null}
import { InfoCircleIcon, Tooltip, TooltipContent, TooltipTrigger } from "@fanvue/ui";

<Tooltip defaultOpen>
  <TooltipTrigger asChild>
    <button type="button" className="text-content-secondary">
      <InfoCircleIcon className="size-5" />
    </button>
  </TooltipTrigger>
  <TooltipContent>Tooltip</TooltipContent>
</Tooltip>
```

## Long Content

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-tooltip--long-content&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="240" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Tooltip — Long Content" />
</Frame>

```tsx theme={null}
import { InfoCircleIcon, Tooltip, TooltipContent, TooltipTrigger } from "@fanvue/ui";

<Tooltip defaultOpen>
  <TooltipTrigger asChild>
    <button type="button" className="text-content-secondary">
      <InfoCircleIcon className="size-5" />
    </button>
  </TooltipTrigger>
  <TooltipContent>
    This is a longer tooltip that demonstrates how the component handles multiline text content.
  </TooltipContent>
</Tooltip>
```

## All Placements

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-tooltip--all-placements&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="520" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Tooltip — All Placements" />
</Frame>

```tsx theme={null}
import { InfoCircleIcon, Tooltip, TooltipContent, TooltipTrigger } from "@fanvue/ui";

function Example() {
  const placements = [
    "top-start",
    "top",
    "top-end",
    "left-start",
    "spacer-1",
    "right-start",
    "left",
    "spacer-2",
    "right",
    "left-end",
    "spacer-3",
    "right-end",
    "bottom-start",
    "bottom",
    "bottom-end",
  ] as const;
  return (
    <div className="grid grid-cols-3 place-items-center gap-24 py-24">
      {placements.map((slot) =>
        slot.startsWith("spacer") ? (
          <div key={slot} />
        ) : (
          <Tooltip key={slot} defaultOpen>
            <TooltipTrigger asChild>
              <button type="button" className="text-content-secondary">
                <InfoCircleIcon className="size-5" />
              </button>
            </TooltipTrigger>
            <TooltipContent placement={slot as Exclude<typeof slot, `spacer-${string}`>}>
              {slot}
            </TooltipContent>
          </Tooltip>
        ),
      )}
    </div>
  );
}
```

## Bottom

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-tooltip--bottom&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="240" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Tooltip — Bottom" />
</Frame>

```tsx theme={null}
import { InfoCircleIcon, Tooltip, TooltipContent, TooltipTrigger } from "@fanvue/ui";

<Tooltip defaultOpen>
  <TooltipTrigger asChild>
    <button type="button" className="text-content-secondary">
      <InfoCircleIcon className="size-5" />
    </button>
  </TooltipTrigger>
  <TooltipContent placement="bottom">Tooltip</TooltipContent>
</Tooltip>
```

## Label as trigger (dashed underline)

<Frame>
  <iframe src={"https://main--697a1b6dd4dad73ee9c0e5f5.chromatic.com/iframe.html?id=components-tooltip--label-as-trigger&viewMode=story&shortcuts=false&singleStory=true&globals=theme:light"} width="100%" height="240" style={{border: "none", borderRadius: "8px"}} loading="lazy" title="Tooltip — Label as trigger (dashed underline)" />
</Frame>

```tsx theme={null}
import { TooltipLabel } from "@fanvue/ui";

<div className="flex flex-col gap-1">
  <TooltipLabel tooltip="Total earnings for the selected period.">Total Earnings</TooltipLabel>
  <span className="typography-header-heading-xl text-content-primary">$128,046.73</span>
</div>
```

## Props

## Tooltip

Root component that manages open/close state for a single tooltip.

A direct re-export of the Radix `TooltipPrimitive.Root` primitive. It accepts all of that primitive's props, unchanged.

## TooltipContent

<ParamField path="asChild" type="boolean" />

<ParamField path="placement" type="&#x22;top&#x22; | &#x22;bottom&#x22; | &#x22;left&#x22; | &#x22;right&#x22; | &#x22;top-start&#x22; | &#x22;top-end&#x22; | &#x22;bottom-start&#x22; | ..." default="top">
  Position of the tooltip relative to the trigger. Takes precedence over `side` and `align`.

  Full type: `"top" | "bottom" | "left" | "right" | "top-start" | "top-end" | "bottom-start" | "bottom-end" | "left-start" | "left-end" | "right-start" | "right-end"`.
</ParamField>

<ParamField path="title" type="ReactNode">
  Optional heading above the body, for the two-row tooltip: a bold label naming the thing, then a plain-weight description of it. Without it the tooltip is a single bold line.
</ParamField>

## TooltipLabel

A text label that is itself the tooltip trigger, marked by a dashed underline. Use this instead of pairing a label with a separate info glyph: the visible text becomes the trigger's accessible name, and the row stays at text height rather than being stretched by an icon button.

The label is repeated as the tooltip's heading, so the tooltip reads as the two-row block the design specifies — the term, then what it means.

Tapping the label toggles the tooltip on touch devices, where there is no hover to trigger it. Tapping elsewhere, scrolling, or opening another tooltip dismisses it.

<ParamField path="children" type="ReactNode" required>
  The label text, which doubles as the trigger.
</ParamField>

<ParamField path="tooltip" type="ReactNode" required>
  Tooltip content. Pass a translated string for i18n.
</ParamField>

## TooltipProvider

Provides tooltip delay and skip-delay context. Wrap your app or a subtree.

Defaults `delayDuration` to 200ms rather than inheriting Radix's 700ms, which reads as unresponsive on the short hint labels this library uses tooltips for. Pass `delayDuration` to override.

Note that `TooltipLabel`, `ChartCard` and `SwitchField` each mount their own provider internally, so they take this default but not an app-level override.

Accepts all props of the underlying Radix `TooltipPrimitive.Provider` primitive, plus `className`.

## TooltipTrigger

The element that triggers the tooltip on hover/focus.

A direct re-export of the Radix `TooltipPrimitive.Trigger` primitive. It accepts all of that primitive's props, unchanged.

## Exported types

Also exported from `@fanvue/ui`: `TooltipContentProps`, `TooltipLabelProps`, `TooltipPlacement`, `TooltipProps`, `TooltipProviderProps`, `TooltipTriggerProps`.

***

**Setup:** [Installation](/docs/ui/installation) · [Theming](/docs/ui/theming)
