OverlaysReact
A popup that appears when an element is hovered or focused, showing a hint for sighted users.
Rendered by React 19.3.1
Installation
npm i @hamur/reactNot on npm yet. The package goes out under the chosen name.
Anatomy
Import the component and assemble its parts:
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger />
<Tooltip.Portal>
<Tooltip.Positioner>
<Tooltip.Popup>
<Tooltip.Arrow />
</Tooltip.Popup>
</Tooltip.Positioner>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
// Not in this example: Tooltip.ViewportExamples
Detached Triggers Simple
A Trigger outside Root is tied to it with a handle.
Detached Triggers Controlled
open, onOpenChange and triggerId control one tooltip from several triggers.
Detached Triggers Full
Viewport animates the content as the tooltip moves between triggers.
API reference
37 props across 8 parts, in React syntax. className, style, render are listed once, under Shared props.
ArrowTooltip.Arrow
Displays an element positioned against the tooltip anchor. Renders a <div>.
| Data attribute | Description |
|---|---|
data-open | Present when the tooltip is open. |
data-closed | Present when the tooltip is closed. |
data-side | Indicates which side the popup is positioned relative to the trigger. |
data-align | Indicates how the popup is aligned relative to specified side. |
data-uncentered | Present when the tooltip arrow is uncentered. |
data-instant | Present if animations should be instant. |
PopupTooltip.Popup
A container for the tooltip contents. Renders a <div>.
| Data attribute | Description |
|---|---|
data-open | Present when the tooltip is open. |
data-closed | Present when the tooltip is closed. |
data-starting-style | Present when the tooltip begins animating in. |
data-ending-style | Present when the tooltip is animating out. |
data-side | Indicates which side the popup is positioned relative to the trigger. |
data-align | Indicates how the popup is aligned relative to specified side. |
data-instant | Present if animations should be instant. |
PortalTooltip.Portal
A portal element that moves the popup to a different part of the DOM. By default, the portal element is appended to <body>. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
containerA parent element to render the portal element into. | HTMLElement | ShadowRoot | React.RefObject<HTMLElement | ShadowRoot | null> | null | — |
keepMountedWhether to keep the portal mounted in the DOM while the popup is hidden. | boolean | false |
PositionerTooltip.Positioner
Positions the tooltip against the trigger. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
disableAnchorTrackingWhether to disable the popup from tracking any layout shift of its positioning anchor. | boolean | false |
alignHow to align the popup relative to the specified side. | Align | 'center' |
alignOffsetAdditional offset along the alignment axis in pixels. | number | OffsetFunction | 0 |
sideWhich side of the anchor element to align the popup against. | Side | 'top' |
sideOffsetDistance between the anchor and the popup in pixels. | number | OffsetFunction | 0 |
arrowPaddingMinimum distance to maintain between the arrow and the edges of the popup. | number | 5 |
anchorAn element to position the popup against. | Element | VirtualElement | React.RefObject<Element | null> | (() => Element | VirtualElement | null) | null | — |
collisionAvoidanceDetermines how to handle collisions when positioning the popup. | CollisionAvoidance | — |
collisionBoundaryAn element or a rectangle that delimits the area that the popup is confined to. | Boundary | 'clipping-ancestors' |
collisionPaddingAdditional space to maintain from the edge of the collision boundary. | Padding | 5 |
stickyWhether to maintain the popup in the viewport after | boolean | false |
positionMethodDetermines which CSS position property to use. | "absolute" | "fixed" | 'absolute' |
| Data attribute | Description |
|---|---|
data-open | Present when the tooltip is open. |
data-closed | Present when the tooltip is closed. |
data-anchor-hidden | Present when the anchor is hidden. |
data-side | Indicates which side the popup is positioned relative to the trigger. |
data-align | Indicates how the popup is aligned relative to specified side. |
| CSS variable | Description |
|---|---|
--available-width | The available width between the trigger and the edge of the viewport. |
--available-height | The available height between the trigger and the edge of the viewport. |
--anchor-width | The anchor's width. |
--anchor-height | The anchor's height. |
--transform-origin | The coordinates that this element is anchored to. Used for animations and transitions. |
--positioner-width | The width of the tooltip's positioner.
It is important to set width to this value when using CSS to animate size changes. |
--positioner-height | The height of the tooltip's positioner.
It is important to set height to this value when using CSS to animate size changes. |
ProviderTooltip.Provider
Provides a shared delay for multiple tooltips. The grouping logic ensures that once a tooltip becomes visible, the adjacent tooltips will be shown instantly.
| Prop | Type | Default |
|---|---|---|
delayHow long to wait before opening the tooltip on hover. | number | — |
closeDelayHow long to wait before closing a tooltip. | number | — |
timeoutAnother tooltip will open instantly if the previous tooltip | number | 400 |
children | React.ReactNode | — |
RootTooltip.Root
Groups all parts of the tooltip. Doesn’t render its own element.
| Prop | Type | Default |
|---|---|---|
defaultOpenWhether the tooltip is initially open. | boolean | false |
openWhether the tooltip is currently open. | boolean | — |
onOpenChangeEvent handler called when the tooltip is opened or closed. | ((open: boolean, eventDetails: TooltipRootChangeEventDetails) => void) | — |
actionsRefA ref to imperative actions. | React.RefObject<TooltipRootActions | null> | — |
defaultTriggerIdID of the trigger that the tooltip is associated with. | string | null | — |
handleA handle to associate the tooltip with a trigger. | TooltipHandle<Payload> | — |
onOpenChangeCompleteEvent handler called after any animations complete when the tooltip is opened or closed. | ((open: boolean) => void) | — |
triggerIdID of the trigger that the tooltip is associated with. | string | null | — |
trackCursorAxisDetermines which axis the tooltip should track the cursor on. | "none" | "both" | "x" | "y" | 'none' |
disabledWhether the tooltip is disabled. | boolean | false |
disableHoverablePopupWhether the tooltip contents can be hovered without closing the tooltip. | boolean | false |
childrenThe content of the tooltip. | React.ReactNode | PayloadChildRenderFunction<Payload> | — |
TriggerTooltip.Trigger
An element to attach the tooltip to. Renders a <button>.
| Prop | Type | Default |
|---|---|---|
closeOnClickWhether the tooltip should close when this trigger is clicked. | boolean | true |
handleA handle to associate the trigger with a tooltip. | TooltipHandle<Payload> | — |
payloadA payload to pass to the tooltip when it is opened. | Payload | — |
disabledIf true, the tooltip will not open when interacting with this trigger. | boolean | false |
delayHow long to wait before opening the tooltip on hover. | number | 600 |
closeDelayHow long to wait before closing the tooltip. | number | 0 |
| Data attribute | Description |
|---|---|
data-popup-open | Present when the corresponding tooltip is open. |
data-trigger-disabled | Present when the trigger is disabled, either by the disabled prop or by a parent <Tooltip.Root> component. |
ViewportTooltip.Viewport
A viewport for displaying content transitions. This component is only required if one popup can be opened by multiple triggers, its content changes based on the trigger, and switching between them is animated. Renders a <div>.
| Prop | Type | Default |
|---|---|---|
childrenThe content to render inside the transition container. | React.ReactNode | — |
| Data attribute | Description |
|---|---|
data-current | Applied to the direct child of the viewport when no transitions are present or the new content when it's entering. |
data-previous | Applied to the direct child of the viewport that contains the exiting content when transitions are present. |
data-activation-direction | Indicates the direction from which the popup was activated. This can be used to create directional animations based on how the popup was triggered. Contains space-separated values for both horizontal and vertical axes. |
data-transitioning | Indicates that the viewport is currently transitioning between old and new content. |
data-instant | Present if animations should be instant. |
| CSS variable | Description |
|---|---|
--popup-width | The width of the parent popup. This variable is placed on the 'previous' container and stores the width of the popup when the previous content was rendered. It can be used to freeze the dimensions of the popup when animating between different content. |
--popup-height | The height of the parent popup. This variable is placed on the 'previous' container and stores the height of the popup when the previous content was rendered. It can be used to freeze the dimensions of the popup when animating between different content. |
Shared props
Every part that renders an element takes these.
| Prop | Type |
|---|---|
classNameCSS class applied to the element, or a function that
returns a class based on the component's state. | string | ((state: State) => string | undefined) |
styleStyle applied to the element, or a function that
returns a style object based on the component's state. | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) |
renderAllows you to replace the component's HTML element
with a different tag, or compose it with another component. | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, State> |
Keyboard and accessibility
Keyboard
| Keys | Does | Part |
|---|---|---|
| Tab | Focusing Trigger opens the tooltip | Trigger |
| Escape | Closes the tooltip | Popup |
Accessibility
| Part | Sets | So that |
|---|---|---|
| Popup | no role and no link to Trigger | the hint is not read twice; touch and screen reader users do not depend on it |
| Trigger | needs an aria-label that matches the tooltip's text | every user gets the same name for the control |
| Arrow | aria-hidden="true" | the decorative arrow is not read |
Focus order
- Trigger is the tab stop; focus never moves into Popup.
- Focusing Trigger opens the tooltip, and leaving it or pressing
Escapecloses it.