Popover
Renders arbitrary content in a floating panel positioned directly below an anchor element. The popover and its transparent backdrop are inserted into document.body via a React portal. It can be dismissed by clicking the backdrop or pressing the Escape key. The position is calculated from the anchor element's bounding rect and updates when isOpen or the anchor changes.
Props
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| content | ReactNode | Yes | — | Content rendered inside the floating panel. |
| anchorRef | React.RefObject<HTMLElement> | Yes | — | Ref to the element the popover is anchored to. |
| isOpen | boolean | Yes | — | Controls whether the popover is visible. |
| onClose | () => void | Yes | — | Callback fired when the backdrop is clicked or Escape is pressed. |
| hasShadow | boolean | No | true | Adds a drop shadow to the floating panel. |
| zIndex | number | No | 9999999 | Base z-index for the backdrop; the panel uses zIndex + 1. |
| containerStyle | React.CSSProperties | No | {} | Inline styles for the floating panel. |
| backdropStyle | React.CSSProperties | No | {} | Inline styles for the transparent backdrop. |
Usage
Basic
import { useRef, useState } from 'react';
import Popover from '@/components/Popover';
export default function Example() {
const anchorRef = useRef<HTMLButtonElement>(null);
const [open, setOpen] = useState(false);
return (
<>
<button ref={anchorRef} onClick={() => setOpen(true)}>
Open Popover
</button>
<Popover
anchorRef={anchorRef}
isOpen={open}
onClose={() => setOpen(false)}
content={
<ul>
<li>Option A</li>
<li>Option B</li>
<li>Option C</li>
</ul>
}
/>
</>
);
}
Custom width and no shadow
import { useRef, useState } from 'react';
import Popover from '@/components/Popover';
export default function Example() {
const anchorRef = useRef<HTMLInputElement>(null);
const [open, setOpen] = useState(false);
return (
<>
<input ref={anchorRef} onFocus={() => setOpen(true)} placeholder="Search..." />
<Popover
anchorRef={anchorRef}
isOpen={open}
onClose={() => setOpen(false)}
hasShadow={false}
containerStyle={{ width: 300, padding: 8 }}
content={<p>Suggestions will appear here.</p>}
/>
</>
);
}