Skip to content
Entangle UI v0.13.0

Popover

Floating content container for interactive content anchored to a trigger element. Built on @floating-ui/react for robust positioning with collision detection, flip/shift behavior, and scroll-aware auto-updating. Uses a compound component pattern with Popover, PopoverTrigger, PopoverContent, and PopoverClose.

Live Preview

import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverClose,
} from 'entangle-ui';
<Popover>
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<p>Popover content here</p>
</PopoverContent>
</Popover>

The placement prop controls where the popover appears relative to the trigger. Supports 12 positions with automatic collision detection.

<Popover placement="bottom-start">
<PopoverTrigger>
<Button>Bottom Start</Button>
</PopoverTrigger>
<PopoverContent>
<p>Placed at bottom-start</p>
</PopoverContent>
</Popover>
<Popover placement="right">
<PopoverTrigger>
<Button>Right</Button>
</PopoverTrigger>
<PopoverContent>
<p>Placed on the right</p>
</PopoverContent>
</Popover>

| Placement | Description | | -------------------------------------- | -------------------- | | top, top-start, top-end | Above the trigger | | bottom, bottom-start, bottom-end | Below the trigger | | left, left-start, left-end | Left of the trigger | | right, right-start, right-end | Right of the trigger |

Use open and onOpenChange for controlled mode.

const [isOpen, setIsOpen] = useState(false);
<Popover open={isOpen} onOpenChange={setIsOpen}>
<PopoverTrigger>
<Button>Toggle</Button>
</PopoverTrigger>
<PopoverContent>
<p>Controlled popover</p>
<Button onClick={() => setIsOpen(false)}>Close</Button>
</PopoverContent>
</Popover>;

Use PopoverClose for a built-in close button inside the popover.

<Popover>
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent>
<PopoverClose />
<h3>Settings</h3>
<p>Configure your preferences.</p>
</PopoverContent>
</Popover>

PopoverContent accepts width, maxHeight, and padding for layout control.

<Popover>
<PopoverTrigger>
<Button>Open</Button>
</PopoverTrigger>
<PopoverContent width={300} maxHeight={400} padding="lg">
<p>Fixed width, scrollable content with large padding.</p>
</PopoverContent>
</Popover>

Set matchTriggerWidth to make the popover content width match the trigger element.

<Popover matchTriggerWidth>
<PopoverTrigger>
<Button fullWidth>Select Option</Button>
</PopoverTrigger>
<PopoverContent>
<p>Same width as the button above</p>
</PopoverContent>
</Popover>

Control the distance between the trigger and popover with the offset prop (in pixels).

<Popover offset={16}>
<PopoverTrigger>
<Button>More space</Button>
</PopoverTrigger>
<PopoverContent>
<p>16px from the trigger</p>
</PopoverContent>
</Popover>

Control how the popover closes.

{
/* Disable close on outside click */
}
<Popover closeOnClickOutside={false}>
<PopoverTrigger>
<Button>Persistent</Button>
</PopoverTrigger>
<PopoverContent>
<p>Only closes via close button or Escape</p>
<PopoverClose />
</PopoverContent>
</Popover>;
{
/* Disable close on Escape */
}
<Popover closeOnEscape={false}>
<PopoverTrigger>
<Button>No Escape</Button>
</PopoverTrigger>
<PopoverContent>
<p>Escape key does not close this</p>
</PopoverContent>
</Popover>;
Prop Type Default Description
children ReactNode PopoverTrigger and PopoverContent elements.
open boolean Whether the popover is open (controlled mode).
defaultOpen boolean false Default open state (uncontrolled mode).
placement 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'left-start' | 'left-end' | 'right' | 'right-start' | 'right-end' 'bottom-start' Popover placement relative to the trigger.
offset number 8 Distance in pixels from the trigger element.
closeOnClickOutside boolean true Whether clicking outside closes the popover.
closeOnEscape boolean true Whether pressing Escape closes the popover.
returnFocus boolean true Whether to return focus to the trigger when popover closes.
portal boolean true Whether to render the popover in a React Portal.
matchTriggerWidth boolean false Whether the popover content width matches the trigger width.
onOpenChange (open: boolean) => void Callback when the open state changes.
Prop Type Default Description
children ReactNode Popover content -- any React elements.
width number | string Width of the popover content. Number = pixels, string = CSS value.
maxHeight number | string Maximum height with scroll.
padding 'none' | 'sm' | 'md' | 'lg' 'md' Padding inside the popover using theme spacing tokens.
Prop Type Default Description
children ReactNode Close button content. Defaults to a built-in X icon.
  • Built on @floating-ui/react with useClick, useDismiss interaction hooks
  • Focus is returned to the trigger when the popover closes (configurable via returnFocus)
  • Escape key dismisses the popover by default
  • Popover content is rendered in a Portal to avoid clipping and z-index issues
  • Uses proper ARIA attributes for trigger/content association
  • Keyboard accessible: Enter/Space to toggle, Escape to close, Tab to navigate within content