Skip to main content
Use Tooltip for a short explanation of a control or truncated text. Keep essential information visible, give controls an accessible name, and use Popover when the content contains links, buttons, or other controls.

Usage

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.

Rich content and composition

Shorthand accepts description and startIcon beside content. Custom node content renders as supplied unless a description or icon requests the title layout.
Compound usage exposes every installed Base UI part and the optional Tooltip.Body layout. Assemble the portal, positioning, popup and optional arrow explicitly. Popup renders its children as supplied; Body provides the same title, description and decorative icon layout as shorthand.
Tooltip.Body accepts optional title children, description and startIcon nodes. Titles use medium weight; descriptions use the secondary tooltip color, preserve line breaks and wrap long text. Omit title children for a description-only tooltip. The icon is decorative and appears only with a title. Body adds no tooltip role, popup styling, sizing or positioning. Arbitrary Popup content remains supported. Import TooltipBodyProps from twenty-ui/primitives/surfaces when typing a wrapper. Every DOM part accepts native props, refs, and element or callback render composition. Shorthand’s top-level native props, render and ref target Popup. Use triggerProps, positionerProps and portalProps to customize the other targets; these override shorthand defaults. Children supply the default trigger render element. Both forms preserve controlled/uncontrolled Root state and Base UI callback event details, including cancellation, reason, original event and active trigger. Tooltip.createHandle<TPayload>() connects detached triggers to either form through handle. Compound Root’s children or shorthand’s content can be a function receiving the typed active payload. Tooltip.Handle and the public TooltipHandle type expose the installed handle contract. Handles support imperative open(triggerId) and close() while their Root is mounted.

Migration

Replace content={<Tooltip.Content description={description} startIcon={icon}>title</Tooltip.Content>} with content={title} description={description} startIcon={icon}. In compound usage, use Tooltip.Body for the shared title and description layout or compose your own content. Tooltip.Content and TooltipContentProps are removed. Existing compound Popup positioning props move to Positioner. Wrap it in Portal, move container and keepMounted to Portal, keep maxWidth on Popup, and replace arrow with an Arrow child. Preserve the former spacing explicitly with sideOffset={10} when needed. Compound Positioner keeps Base UI’s sideOffset={0}. Both forms cap Popup at 300 pixels by default.

Disabled controls

Native disabled buttons cannot receive keyboard focus. Wrap one in a focusable trigger so users can discover why the action is unavailable.
Setting disabled on shorthand or Root suppresses the tooltip itself. Trigger disabled suppresses that trigger’s tooltip interaction. Disable the native control through its own props or Trigger’s render element.

Placement and overflowing text

Shorthand defaults to side="top", align="center", and sideOffset={10}. Both shorthand and compound tooltips have a maximum width of 300 pixels, capped by the available space beside the anchor. Pass maxWidth to shorthand or Tooltip.Popup to choose a different maximum, including wider previews. Native popup styles remain available for custom sizing. Placement adjusts to available space. An open tooltip hides while its anchor is scrolled out of view, including out of a scroll container. Use arrow for an arrow and container to override the theme’s portal destination; see 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.
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.
"center" | "end" | "start"
default:"center"
Alignment relative to the trigger. Defaults to center.
number | OffsetFunction
default:"0"
Offset along the alignment axis in pixels.
Element | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null) | null
An explicit positioning anchor for the popup.
boolean
Displays an arrow pointing to the trigger. Defaults to false.
number
default:"5"
Minimum distance from the arrow to the popup edges.
ReactElement<unknown, string | JSXElementConstructor<any>>
required
A single trigger element. Custom components must forward their ref, native attributes, and event handlers.
string | ((state: TooltipPopupState) => string | undefined)
Additional CSS class for the popup.
number
default:"0"
Delay in milliseconds before closing after hover ends. Defaults to 0.
boolean
default:"true"
Whether the tooltip should close when this trigger is clicked.
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'.
Boundary
default:"clipping-ancestors"
An element or a rectangle that delimits the area that the popup is confined to.
Padding
default:"5"
Additional space to maintain from the edge of the collision boundary.
HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null
Portal destination. Defaults to the current theme container.
ReactNode | PayloadChildRenderFunction<TPayload>
required
Supplementary content, or a function receiving the active trigger payload. Strings and numbers use the shorthand title layout.
boolean
default:"false"
Initial visibility when the tooltip manages its own state.
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.
number
default:"600"
Delay in milliseconds before opening on hover. Defaults to 600.
ReactNode
Optional secondary text below the shorthand title.
boolean
default:"false"
Whether to disable the popup from tracking any layout shift of its positioning anchor.
boolean
default:"false"
Prevents the tooltip from opening.
boolean
default:"false"
Prevents hovering over the popup from keeping it open.
TooltipHandle<TPayload>
Connects detached triggers and preserves their typed payloads.
boolean
Keeps the popup mounted while closed.
MaxWidth<string | number>
Maximum popup width. Defaults to 300 pixels and is capped by the space available beside the anchor.
((open: boolean, eventDetails: TooltipRootChangeEventDetails) => void)
Receives the requested open state and unchanged Base UI event details, including reason, event, trigger and cancel().
((open: boolean) => void)
Event handler called after any animations complete when the tooltip is opened or closed.
boolean
Controlled visibility of the tooltip.
TooltipPortalProps
Full Portal props, including native props, ref and render. Overrides shorthand portal defaults.
TooltipPositionerProps
Full Positioner props, including native props, ref and render. Overrides shorthand placement defaults.
"absolute" | "fixed"
default:"absolute"
CSS positioning method for the popup.
Ref<HTMLDivElement>
Ref forwarded to the popup element.
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.
"bottom" | "inline-end" | "inline-start" | "left" | "right" | "top"
default:"top"
Preferred side of the trigger. Defaults to top and may change to avoid collisions.
number | OffsetFunction
default:"10"
Distance from the trigger in pixels. Defaults to 10.
ReactNode
Optional node before the shorthand title.
boolean
default:"false"
Whether to maintain the popup in the viewport after the anchor element was scrolled out of view.
CSSProperties | ((state: TooltipPopupState) => CSSProperties | undefined)
Inline styles for the popup.
"both" | "none" | "x" | "y"
default:"none"
Determines which axis the tooltip should track the cursor on.
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).
TooltipTriggerProps<TPayload>
Full Trigger props, including native props, ref, render and payload. Overrides the shorthand trigger defaults.
boolean
Fades and slides the popup out when it closes instead of hiding it at once.

Tooltip.Root

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.
ReactNode | PayloadChildRenderFunction<Payload>
Parts or a render function receiving the active trigger payload. Root renders no DOM node.
boolean
default:"false"
Whether the tooltip is initially open.To render a controlled tooltip, use the open prop instead.
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.
boolean
default:"false"
Whether the tooltip is disabled.
boolean
default:"false"
Whether the tooltip contents can be hovered without closing the tooltip.
TooltipHandle<Payload>
Connects detached triggers and imperative open/close actions.
((open: boolean, eventDetails: TooltipRootChangeEventDetails) => void)
Receives the requested open state and unchanged Base UI event details, including reason, event, trigger and cancel().
((open: boolean) => void)
Event handler called after any animations complete when the tooltip is opened or closed.
boolean
Whether the tooltip is currently open.
"both" | "none" | "x" | "y"
default:"none"
Determines which axis the tooltip should track the cursor on.
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).

Tooltip.Trigger

string | ((state: TooltipTriggerState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
number
default:"0"
How long to wait before closing the tooltip. Specified in milliseconds.
boolean
default:"true"
Whether the tooltip should close when this trigger is clicked.
number
default:"600"
How long to wait before opening the tooltip on hover. Specified in milliseconds.
boolean
default:"false"
Disables tooltip interaction for this trigger without disabling its native element.
TooltipHandle<Payload>
A handle to associate the trigger with a tooltip.
Payload
A payload to pass to the tooltip when it is opened.
((((instance: HTMLButtonElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<HTMLButtonElement | null>) & (((instance: HTMLElement | null) => void | (() => VoidOrUndefinedOnly)) | RefObject<...>)) | null
Ref to the rendered trigger element, a button by default.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TooltipTriggerState>
Composes a native element or a component that forwards attributes, handlers and ref.
CSSProperties | ((state: TooltipTriggerState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.

Tooltip.Portal

string | ((state: TooltipPortalState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
HTMLElement | ShadowRoot | RefObject<HTMLElement | ShadowRoot | null> | null
Portal destination. Defaults to the current theme container, then the document body.
boolean
default:"false"
Whether to keep the portal mounted in the DOM while the popup is hidden.
Ref<HTMLDivElement>
Ref to the portal div.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TooltipPortalState>
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.
CSSProperties | ((state: TooltipPortalState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.

Tooltip.Positioner

"center" | "end" | "start"
default:"center"
How to align the popup relative to the specified side.
number | OffsetFunction
default:"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.
Element | VirtualElement | RefObject<Element | null> | (() => Element | VirtualElement | null) | null
An element to position the popup against. By default, the popup will be positioned against the trigger.
number
default:"5"
Minimum distance to maintain between the arrow and the edges of the popup.Use it to prevent the arrow element from hanging out of the rounded corners of a popup.
string | ((state: TooltipPositionerState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
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'.
Boundary
default:"clipping-ancestors"
An element or a rectangle that delimits the area that the popup is confined to.
Padding
default:"5"
Additional space to maintain from the edge of the collision boundary.
boolean
default:"false"
Whether to disable the popup from tracking any layout shift of its positioning anchor.
"absolute" | "fixed"
default:"absolute"
Determines which CSS position property to use.
Ref<HTMLDivElement>
Ref to the positioning div. Native props, styles and render target this element.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TooltipPositionerState>
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.
"bottom" | "inline-end" | "inline-start" | "left" | "right" | "top"
default:"top"
Preferred physical or logical side of the anchor. Defaults to top.
number | OffsetFunction
default:"0"
Distance from the anchor. Defaults to 0 in compound usage. Accepts a number or positioning function.
boolean
default:"false"
Whether to maintain the popup in the viewport after the anchor element was scrolled out of view.
CSSProperties | ((state: TooltipPositionerState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.

Tooltip.Popup

ReactNode
Content rendered as supplied. Does not create a portal, positioner, title layout or arrow.
string | ((state: TooltipPopupState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
MaxWidth<string | number>
Maximum popup width. Defaults to 300 pixels and is capped by the space available beside the anchor.
Ref<HTMLDivElement>
Ref to the popup div. Native props, styles and render target this element.
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.
CSSProperties | ((state: TooltipPopupState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.
boolean
default:"false"
Enables the optional Twenty exit transition.

Tooltip.Body

ReactNode
Optional title content, displayed with medium weight. Omit it for a description-only tooltip.
ReactNode
Optional secondary content. Preserves line breaks and wraps long text.
Ref<HTMLDivElement>
Ref to the body div. Native props, styles and render target this element.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, {}>
Composes the body root through an element or render callback while preserving its layout and content.
ReactNode
Optional decorative node before the title. Omitted when the title is empty.

Tooltip.Arrow

string | ((state: TooltipArrowState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
Ref<HTMLDivElement>
Ref to the arrow div. Compose inside Popup.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TooltipArrowState>
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.
CSSProperties | ((state: TooltipArrowState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.

Tooltip.Viewport

ReactNode
The content to render inside the transition container.
string | ((state: TooltipViewportState) => string | undefined)
CSS class applied to the element, or a function that returns a class based on the component’s state.
Ref<HTMLDivElement>
Ref to the content-transition div. Useful when several triggers share changing content.
ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, TooltipViewportState>
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.
CSSProperties | ((state: TooltipViewportState) => CSSProperties | undefined)
Style applied to the element, or a function that returns a style object based on the component’s state.

Tooltip.Provider

ReactNode
Tooltips sharing delay, closeDelay and timeout configuration. Provider renders no DOM node.
number
How long to wait before closing a tooltip. Specified in milliseconds.
number
How long to wait before opening the tooltip on hover. Specified in milliseconds.
number
default:"400"
Another tooltip will open instantly if the previous tooltip is closed within this timeout. Specified in milliseconds.