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

# Tooltip

> Show supplementary information when a trigger is hovered or focused.

export const StoryEmbed = ({storyId, title, height = 240}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

Use `Tooltip` for a short explanation of a control or truncated text. Keep essential information visible, give controls an accessible name, and use [Popover](/ui/primitives/surfaces/popover) when the content contains links, buttons, or other controls.

<StoryEmbed storyId="ui-surfaces-tooltip--documentation" title="Tooltip example" />

## Single trigger

```tsx theme={null}
import { Button } from 'twenty-ui/primitives/input';
import { Tooltip } from 'twenty-ui/primitives/surfaces';

export const ExportHelp = () => (
  <Tooltip content="Download the visible records as a CSV file" side="top">
    <span>
      <Button>Export records</Button>
    </span>
  </Tooltip>
);
```

The convenience component accepts one trigger element as `children`. Native elements receive the trigger attributes, event handlers, and ref directly. Custom trigger components must forward all of them. A wrapper element also works with a component that does not forward every trigger prop.

Hover opens the tooltip after `delay` milliseconds, which defaults to `600`. Keyboard focus opens it immediately. `closeDelay` defaults to `0`; hovering over the popup keeps it open unless `disableHoverablePopup` is set. Escape dismisses it.

## Controlled state

Use `open` and `onOpenChange` together when the application owns visibility. Use `defaultOpen` only to set the initial visibility of an uncontrolled tooltip.

```tsx theme={null}
import { useState } from 'react';
import { Button } from 'twenty-ui/primitives/input';
import { Tooltip } from 'twenty-ui/primitives/surfaces';

export const ControlledExportHelp = () => {
  const [open, setOpen] = useState(false);

  return (
    <Tooltip
      content="Download the visible records as a CSV file"
      open={open}
      onOpenChange={setOpen}
      delay={300}
    >
      <span>
        <Button>Export records</Button>
      </span>
    </Tooltip>
  );
};
```

## Rich content and composition

`Tooltip.Content` provides a title, optional description, and optional leading icon. Use it as `content` or inside `Tooltip.Popup`.

```tsx theme={null}
import { IconInfoCircle } from 'twenty-ui/icon';
import { Button } from 'twenty-ui/primitives/input';
import { Tooltip } from 'twenty-ui/primitives/surfaces';

export const ExportDetails = () => (
  <Tooltip.Root>
    <Tooltip.Trigger render={<span />}>
      <Button>Export records</Button>
    </Tooltip.Trigger>
    <Tooltip.Popup side="right" align="start" arrow>
      <Tooltip.Content
        startIcon={<IconInfoCircle />}
        description="Only the records matching your current filters are included."
      >
        Export visible records
      </Tooltip.Content>
    </Tooltip.Popup>
  </Tooltip.Root>
);
```

| Part       | Purpose                                                       |
| ---------- | ------------------------------------------------------------- |
| `Root`     | Coordinates visibility and trigger interactions.              |
| `Trigger`  | Renders the element that opens the tooltip on hover or focus. |
| `Popup`    | Renders positioned content in a portal.                       |
| `Content`  | Styles primary text, a description, and an icon.              |
| `Provider` | Coordinates opening delays across a group of tooltips.        |

`Tooltip.createHandle()` connects detached triggers to a shared `Root` through their `handle` prop. Keep each popup's content supplementary even when several triggers share it.

## Disabled controls

Native disabled buttons cannot receive keyboard focus. Wrap one in a focusable trigger so users can discover why the action is unavailable.

```tsx theme={null}
import { Button } from 'twenty-ui/primitives/input';
import { Tooltip } from 'twenty-ui/primitives/surfaces';

export const UnavailableExport = () => (
  <Tooltip content="Select at least one record to export">
    <span tabIndex={0} aria-label="Export records unavailable">
      <Button disabled>Export records</Button>
    </span>
  </Tooltip>
);
```

Setting `disabled` on `Tooltip` suppresses the tooltip itself. It does not disable the control.

## Placement and overflowing text

The popup defaults to `side="top"`, `align="center"`, `sideOffset={10}`, and a maximum width of `300` pixels. Placement adjusts to available space. Use `arrow` for an arrow and `container` to override the theme's portal destination; see [theming](/ui/theming).

Use `OverflowingTextWithTooltip` when a text label should show its full value only when truncated. Its existing `text`, `tooltipContent`, and `tooltipPlace` props remain available.

## Props

The reference is generated from the public component types. Native popup attributes and event handlers are also accepted.

<ParamField body="actionsRef" type="RefObject<TooltipRootActions | null>">
  A ref to imperative actions.

  * `unmount`: Unmounts the tooltip popup.
  * `close`: Closes the tooltip imperatively when called.
</ParamField>

<ParamField body="align" type="&#x22;center&#x22; | &#x22;end&#x22; | &#x22;start&#x22;">
  Alignment relative to the trigger. Defaults to center.
</ParamField>

<ParamField body="alignOffset" type="number | OffsetFunction" default="0">
  Offset along the alignment axis in pixels.
</ParamField>

<ParamField body="anchor" type="Element | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null) | null">
  An explicit positioning anchor for the popup.
</ParamField>

<ParamField body="arrow" type="boolean">
  Displays an arrow pointing to the trigger. Defaults to false.
</ParamField>

<ParamField body="children" type="ReactElement<unknown, string | JSXElementConstructor<any>>" required>
  A single trigger element. Custom components must forward their ref, native attributes, and event handlers.
</ParamField>

<ParamField body="className" type="string | ((state: TooltipPopupState) => string | undefined)">
  Additional CSS class for the popup.
</ParamField>

<ParamField body="closeDelay" type="number" default="0">
  Delay in milliseconds before closing after hover ends. Defaults to 0.
</ParamField>

<ParamField body="closeOnClick" type="boolean" default="true">
  Whether the tooltip should close when this trigger is clicked.
</ParamField>

<ParamField body="collisionAvoidance" type="CollisionAvoidance">
  Determines how to handle collisions when positioning the popup.

  `side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`):

  * `'flip'`: keep the requested side when it fits; otherwise try the opposite side
    (`top` and `bottom`, or `left` and `right`).
  * `'shift'`: never change side; keep the requested side and move the popup within
    the clipping boundary so it stays visible.
  * `'none'`: do not correct side-axis overflow.

  `align` controls overflow on the alignment axis (`start`/`center`/`end`):

  * `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows.
  * `'shift'`: keep side and requested alignment, then nudge the popup along the
    alignment axis to fit.
  * `'none'`: do not correct alignment-axis overflow.

  `fallbackAxisSide` controls fallback behavior on the perpendicular axis when the
  preferred axis cannot fit:

  * `'start'`: allow perpendicular fallback and try the logical start side first
    (`top` before `bottom`, or `left` before `right` in LTR).
  * `'end'`: allow perpendicular fallback and try the logical end side first
    (`bottom` before `top`, or `right` before `left` in LTR).
  * `'none'`: do not fallback to the perpendicular axis.

  When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`.
  If `align` is omitted, it defaults to `'flip'`.
</ParamField>

<ParamField body="collisionBoundary" type="Boundary" default="clipping-ancestors">
  An element or a rectangle that delimits the area that the popup is confined to.
</ParamField>

<ParamField body="collisionPadding" type="Padding" default="5">
  Additional space to maintain from the edge of the collision boundary.
</ParamField>

<ParamField body="container" type="HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null">
  Portal destination. Defaults to the current theme container.
</ParamField>

<ParamField body="content" type="ReactNode" required>
  Supplementary content displayed in the tooltip.
</ParamField>

<ParamField body="defaultOpen" type="boolean" default="false">
  Initial visibility when the tooltip manages its own state.
</ParamField>

<ParamField body="defaultTriggerId" type="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.
</ParamField>

<ParamField body="delay" type="number" default="600">
  Delay in milliseconds before opening on hover. Defaults to 600.
</ParamField>

<ParamField body="disableAnchorTracking" type="boolean" default="false">
  Whether to disable the popup from tracking any layout shift of its positioning anchor.
</ParamField>

<ParamField body="disabled" type="boolean" default="false">
  Prevents the tooltip from opening.
</ParamField>

<ParamField body="disableHoverablePopup" type="boolean" default="false">
  Prevents hovering over the popup from keeping it open.
</ParamField>

<ParamField body="keepMounted" type="boolean">
  Keeps the popup mounted while closed.
</ParamField>

<ParamField body="maxWidth" type="MaxWidth<string | number>">
  Maximum popup width. Defaults to 300 pixels.
</ParamField>

<ParamField body="onOpenChange" type="((open: boolean, eventDetails: TooltipRootChangeEventDetails) => void)">
  Called when an interaction requests a visibility change.
</ParamField>

<ParamField body="onOpenChangeComplete" type="((open: boolean) => void)">
  Event handler called after any animations complete when the tooltip is opened or closed.
</ParamField>

<ParamField body="open" type="boolean">
  Controlled visibility of the tooltip.
</ParamField>

<ParamField body="positionMethod" type="&#x22;absolute&#x22; | &#x22;fixed&#x22;" default="absolute">
  CSS positioning method for the popup.
</ParamField>

<ParamField body="render" type="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.
</ParamField>

<ParamField body="side" type="&#x22;bottom&#x22; | &#x22;left&#x22; | &#x22;right&#x22; | &#x22;top&#x22;">
  Preferred side of the trigger. Defaults to top and may change to avoid collisions.
</ParamField>

<ParamField body="sideOffset" type="number | OffsetFunction" default="10">
  Distance from the trigger in pixels. Defaults to 10.
</ParamField>

<ParamField body="sticky" type="boolean" default="false">
  Whether to maintain the popup in the viewport after
  the anchor element was scrolled out of view.
</ParamField>

<ParamField body="style" type="CSSProperties | ((state: TooltipPopupState) => CSSProperties | undefined)">
  Inline styles for the popup.
</ParamField>

<ParamField body="trackCursorAxis" type="&#x22;both&#x22; | &#x22;none&#x22; | &#x22;x&#x22; | &#x22;y&#x22;" default="none">
  Determines which axis the tooltip should track the cursor on.
</ParamField>

<ParamField body="triggerId" type="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).
</ParamField>

### Tooltip.Root

<ParamField body="Root.actionsRef" type="RefObject<TooltipRootActions | null>">
  A ref to imperative actions.

  * `unmount`: Unmounts the tooltip popup.
  * `close`: Closes the tooltip imperatively when called.
</ParamField>

<ParamField body="Root.children" type="ReactNode | PayloadChildRenderFunction<Payload>">
  The content of the tooltip.
  This can be a regular React node or a render function that receives the `payload` of the active trigger.
</ParamField>

<ParamField body="Root.defaultOpen" type="boolean" default="false">
  Whether the tooltip is initially open.

  To render a controlled tooltip, use the `open` prop instead.
</ParamField>

<ParamField body="Root.defaultTriggerId" type="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.
</ParamField>

<ParamField body="Root.disabled" type="boolean" default="false">
  Whether the tooltip is disabled.
</ParamField>

<ParamField body="Root.disableHoverablePopup" type="boolean" default="false">
  Whether the tooltip contents can be hovered without closing the tooltip.
</ParamField>

<ParamField body="Root.handle" type="TooltipHandle<Payload>">
  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.
</ParamField>

<ParamField body="Root.onOpenChange" type="((open: boolean, eventDetails: TooltipRootChangeEventDetails) => void)">
  Event handler called when the tooltip is opened or closed.
</ParamField>

<ParamField body="Root.onOpenChangeComplete" type="((open: boolean) => void)">
  Event handler called after any animations complete when the tooltip is opened or closed.
</ParamField>

<ParamField body="Root.open" type="boolean">
  Whether the tooltip is currently open.
</ParamField>

<ParamField body="Root.trackCursorAxis" type="&#x22;both&#x22; | &#x22;none&#x22; | &#x22;x&#x22; | &#x22;y&#x22;" default="none">
  Determines which axis the tooltip should track the cursor on.
</ParamField>

<ParamField body="Root.triggerId" type="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).
</ParamField>

### Tooltip.Trigger

<ParamField body="Trigger.className" type="string | ((state: TooltipTriggerState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="Trigger.closeDelay" type="number" default="0">
  How long to wait before closing the tooltip. Specified in milliseconds.
</ParamField>

<ParamField body="Trigger.closeOnClick" type="boolean" default="true">
  Whether the tooltip should close when this trigger is clicked.
</ParamField>

<ParamField body="Trigger.delay" type="number" default="600">
  How long to wait before opening the tooltip on hover. Specified in milliseconds.
</ParamField>

<ParamField body="Trigger.disabled" type="boolean" default="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.
</ParamField>

<ParamField body="Trigger.handle" type="TooltipHandle<Payload>">
  A handle to associate the trigger with a tooltip.
</ParamField>

<ParamField body="Trigger.payload" type="Payload">
  A payload to pass to the tooltip when it is opened.
</ParamField>

<ParamField body="Trigger.render" type="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.
</ParamField>

<ParamField body="Trigger.style" type="CSSProperties | ((state: TooltipTriggerState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

### Tooltip.Popup

<ParamField body="Popup.align" type="&#x22;center&#x22; | &#x22;end&#x22; | &#x22;start&#x22;" default="center">
  Alignment relative to the trigger. Defaults to center.
</ParamField>

<ParamField body="Popup.alignOffset" type="number | OffsetFunction" default="0">
  Offset along the alignment axis in pixels.
</ParamField>

<ParamField body="Popup.anchor" type="Element | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null) | null">
  An explicit positioning anchor for the popup.
</ParamField>

<ParamField body="Popup.arrow" type="boolean" default="false">
  Displays an arrow pointing to the trigger. Defaults to false.
</ParamField>

<ParamField body="Popup.className" type="string | ((state: TooltipPopupState) => string | undefined)">
  Additional CSS class for the popup.
</ParamField>

<ParamField body="Popup.collisionAvoidance" type="CollisionAvoidance">
  Determines how to handle collisions when positioning the popup.

  `side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`):

  * `'flip'`: keep the requested side when it fits; otherwise try the opposite side
    (`top` and `bottom`, or `left` and `right`).
  * `'shift'`: never change side; keep the requested side and move the popup within
    the clipping boundary so it stays visible.
  * `'none'`: do not correct side-axis overflow.

  `align` controls overflow on the alignment axis (`start`/`center`/`end`):

  * `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows.
  * `'shift'`: keep side and requested alignment, then nudge the popup along the
    alignment axis to fit.
  * `'none'`: do not correct alignment-axis overflow.

  `fallbackAxisSide` controls fallback behavior on the perpendicular axis when the
  preferred axis cannot fit:

  * `'start'`: allow perpendicular fallback and try the logical start side first
    (`top` before `bottom`, or `left` before `right` in LTR).
  * `'end'`: allow perpendicular fallback and try the logical end side first
    (`bottom` before `top`, or `right` before `left` in LTR).
  * `'none'`: do not fallback to the perpendicular axis.

  When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`.
  If `align` is omitted, it defaults to `'flip'`.
</ParamField>

<ParamField body="Popup.collisionBoundary" type="Boundary" default="clipping-ancestors">
  An element or a rectangle that delimits the area that the popup is confined to.
</ParamField>

<ParamField body="Popup.collisionPadding" type="Padding" default="5">
  Additional space to maintain from the edge of the collision boundary.
</ParamField>

<ParamField body="Popup.container" type="HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null">
  Portal destination. Defaults to the current theme container.
</ParamField>

<ParamField body="Popup.disableAnchorTracking" type="boolean" default="false">
  Whether to disable the popup from tracking any layout shift of its positioning anchor.
</ParamField>

<ParamField body="Popup.keepMounted" type="boolean">
  Keeps the popup mounted while closed.
</ParamField>

<ParamField body="Popup.maxWidth" type="MaxWidth<string | number>" default="300px">
  Maximum popup width. Defaults to 300 pixels.
</ParamField>

<ParamField body="Popup.positionMethod" type="&#x22;absolute&#x22; | &#x22;fixed&#x22;" default="absolute">
  CSS positioning method for the popup.
</ParamField>

<ParamField body="Popup.render" type="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.
</ParamField>

<ParamField body="Popup.side" type="&#x22;bottom&#x22; | &#x22;left&#x22; | &#x22;right&#x22; | &#x22;top&#x22;" default="top">
  Preferred side of the trigger. Defaults to top and may change to avoid collisions.
</ParamField>

<ParamField body="Popup.sideOffset" type="number | OffsetFunction" default="10">
  Distance from the trigger in pixels. Defaults to 10.
</ParamField>

<ParamField body="Popup.sticky" type="boolean" default="false">
  Whether to maintain the popup in the viewport after
  the anchor element was scrolled out of view.
</ParamField>

<ParamField body="Popup.style" type="CSSProperties | ((state: TooltipPopupState) => CSSProperties | undefined)">
  Inline styles for the popup.
</ParamField>

### Tooltip.Content

<ParamField body="Content.description" type="ReactNode">
  Secondary explanation beneath the primary text.
</ParamField>

<ParamField body="Content.render" type="ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>">
  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.
</ParamField>

<ParamField body="Content.startIcon" type="ReactNode">
  An icon displayed before the text.
</ParamField>

### Tooltip.Provider

<ParamField body="Provider.closeDelay" type="number">
  How long to wait before closing a tooltip. Specified in milliseconds.
</ParamField>

<ParamField body="Provider.delay" type="number">
  How long to wait before opening the tooltip on hover. Specified in milliseconds.
</ParamField>

<ParamField body="Provider.timeout" type="number" default="400">
  Another tooltip will open instantly if the previous tooltip
  is closed within this timeout. Specified in milliseconds.
</ParamField>
