Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/components/Tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ function TooltipContent({
// Label tooltips are kept in the DOM even when not visually open
if (!open && purpose !== "label") return null;

// Hide the tooltip if it has escaped its boundary (when `boundary` prop is set)
const escaped = floatingContext.middlewareData?.hide?.escaped ?? false;

return (
<FloatingPortal>
<div
Expand All @@ -135,7 +138,7 @@ function TooltipContent({
{...rest.tooltipProps}
{...rest.getFloatingProps()}
className={classNames(styles.tooltip, {
[styles.invisible]: purpose === "label" && !open,
[styles.invisible]: (purpose === "label" && !open) || escaped,
})}
>
<FloatingArrow
Expand Down
24 changes: 24 additions & 0 deletions src/components/Tooltip/useTooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
arrow,
autoUpdate,
flip,
hide,
offset,
type OpenChangeReason,
type Placement,
Expand Down Expand Up @@ -77,6 +78,17 @@ export interface CommonUseTooltipProps {
*/
isTriggerInteractive: boolean;

/**
* An optional boundary element to constrain the tooltip within.
* When provided, the tooltip will be hidden if it escapes this boundary.
* Also passed to the `flip` middleware so it can choose a placement that
* keeps the tooltip inside the boundary.
* Accepts a single Element or an array of Elements. Useful for tooltips
* near containers they should not overlap (e.g. the message composer).
* @default undefined
Comment thread
t3chguy marked this conversation as resolved.
*/
boundary?: Element | null | Element[];

/**
* Additional aria-* attributes to pass through to the floating tooltip for
* edge cases which require more user awareness like errors & alerts.
Expand Down Expand Up @@ -111,6 +123,7 @@ export function useTooltip({
caption,
"aria-atomic": ariaAtomic,
"aria-live": ariaLive,
boundary,
...props
}: UseTooltipProps) {
const labelId = useId();
Expand Down Expand Up @@ -143,8 +156,19 @@ export function useTooltip({
crossAxis: placement.includes("-"),
fallbackAxisSideDirection: "start",
padding: 5,
// Only pass boundary if set — FloatingUI's Boundary type excludes null
...(boundary ? { boundary } : {}),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use boundary: boundary ?? undefined then?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed both.
Dropped null from the type and simplified the middleware.

}),
shift({ padding: 5 }),
...(boundary
? [
hide({
strategy: "escaped",
boundary,
padding: 6,
}),
]
: []),
// add the little arrow along with the floating content
arrow({
element: arrowRef,
Expand Down
Loading