-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Provide a general summary of the issue here
The boundaryElement prop documented on the <Popover> component does not appear to have any effect on positioning or flip behaviour. When a DOM element is passed as boundaryElement, the popover continues to use document.body as its clipping boundary — ignoring the provided element entirely. This means popovers inside constrained containers (scrollable panels, modals, split-pane sidebars, data tables with overflow: hidden) overflow or get clipped instead of flipping/clamping within the intended boundary.
@devongovett @snowystinger any idea on this?
🤔 Expected Behavior?
When boundaryElement is set to a DOM element (e.g. a scrollable container or a modal box), the popover positioning engine should:
- Treat that element as the clipping boundary for collision detection.
- Flip placement (e.g.
bottom → top) when the popover would overflow the boundary element. - Shift/clamp the popover horizontally or vertically to stay within the boundary element's rect.
😯 Current Behavior
Passing boundaryElement={someElement} to <Popover> is silently ignored. The popover positions itself as if the boundary is still document.body, regardless of what element is passed.
Confirmed reproduction scenarios:
| Scenario | Container | Expected | Actual |
|---|---|---|---|
| Scrollable panel | overflow-y: auto div |
Flip upward near bottom | Renders below, clipped |
| Modal dialog | Constrained modal box | Clamp within modal | Bleeds outside modal |
| Split-pane sidebar | Left panel with overflow: hidden |
Stay within left panel | Bleeds into right panel |
| Data table | overflow: auto table wrapper |
Flip & clamp to table | Clips through table border |
No errors or warnings are thrown in the console. The prop is accepted without complaint but produces no observable change in positioning behaviour.
💁 Possible Solution
No response
🔦 Context
The boundaryElement prop is listed in the official API table on the React Aria Components documentation for <Popover>:
boundaryElement—Element— Default:document.body
Element that serves as the positioning boundary.
Given this documented default, the prop clearly intends to override the boundary. The silent no-op behaviour makes it hard to diagnose because there are no console warnings and the popover still renders — just not constrained correctly.
This is particularly impactful for applications that render popovers inside:
- Dashboard panels and sidebar layouts
- Modals that contain form fields with dropdown/popover pickers
- Virtualised lists and data tables
- Any design where
overflow: hiddenoroverflow: autois set on an ancestor
🖥️ Steps to Reproduce
- Install
react-aria-components@1.8.0 - Create a scrollable container with
height: 200px; overflow-y: auto - Render several
<DialogTrigger>+<Button>+<Popover>combos inside it - Pass the scrollable container's DOM element as
boundaryElementon<Popover> - Scroll so a trigger is near the bottom of the container
- Click the trigger button
- Here is a reproducible codesandbox
Observe: Popover renders below the trigger, clipped by the container, instead of flipping upward.
Minimal reproduction (CodeSandbox-ready):
import { useState } from 'react';
import {
DialogTrigger,
Button,
Popover,
Dialog,
} from 'react-aria-components';
const items = Array.from({ length: 8 }, (_, i) => ({
id: i,
label: `Item ${i + 1}`,
}));
export default function App() {
const [boundary, setBoundary] = useState(null);
return (
<div
ref={(el) => { if (el && !boundary) setBoundary(el); }}
style={{
height: 220,
overflowY: 'auto',
border: '1px solid #ccc',
borderRadius: 8,
maxWidth: 400,
margin: '40px auto',
}}
>
{items.map((item) => (
<div
key={item.id}
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
padding: '10px 16px',
borderBottom: '1px solid #eee',
}}
>
<span>{item.label}</span>
<DialogTrigger>
<Button>Open</Button>
{/*
Bug: boundaryElement is ignored.
Items near the bottom should trigger a flip to placement="top",
but the popover renders below and is clipped.
*/}
<Popover
boundaryElement={boundary}
placement="bottom"
style={{ padding: 12, background: 'white', border: '1px solid #ccc', borderRadius: 6 }}
>
<Dialog aria-label={item.label}>
<p>Popover for {item.label}</p>
<p style={{ fontSize: 12, color: '#888' }}>
Should flip upward when near container bottom.
</p>
</Dialog>
</Popover>
</DialogTrigger>
</div>
))}
</div>
);
}Version
1.8.0
What browsers are you seeing the problem on?
Chrome
If other, please specify.
No response
What operating system are you using?
Linux
🧢 Your Company/Team
No response
🕷 Tracking Issue
No response