Skip to content

boundaryElement prop on <Popover> has no effect — popover still positions against document.body #9690

@NarendraKuruva

Description

@NarendraKuruva

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:

  1. Treat that element as the clipping boundary for collision detection.
  2. Flip placement (e.g. bottom → top) when the popover would overflow the boundary element.
  3. 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>:

boundaryElementElement — 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: hidden or overflow: auto is set on an ancestor

🖥️ Steps to Reproduce

  1. Install react-aria-components@1.8.0
  2. Create a scrollable container with height: 200px; overflow-y: auto
  3. Render several <DialogTrigger> + <Button> + <Popover> combos inside it
  4. Pass the scrollable container's DOM element as boundaryElement on <Popover>
  5. Scroll so a trigger is near the bottom of the container
  6. Click the trigger button
  7. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions