usePopover
Hook that manages popover open state, outside click dismissal, escape key handling, and focus management.
Usage#
import { usePopover } from '@primereact/headless/popover';
import { usePortal } from '@primereact/headless/portal';
import { usePositioner } from '@primereact/headless/positioner';
import { createPortal } from 'react-dom';
const { triggerProps, popupProps, positionerProps, arrowProps, closeProps, state } = usePopover();
const portal = usePortal();
usePositioner({
anchor: state.anchorElement,
content: state.positionerElement,
arrow: state.arrowElement,
side: 'bottom',
flip: true,
shift: true
});
return (
<>
<button {...triggerProps}></button>;
{
portal.state.mounted &&
state.open &&
createPortal(
<div {...positionerProps}>
<div {...popupProps}>
<div {...arrowProps} />
<button {...closeProps}></button>
</div>
</div>,
document.body
);
}
</>
);usePopover manages open/close state, outside click dismissal, escape key handling, and optional focus trapping. Use usePositioner for anchor-relative positioning and usePortal with createPortal for body portaling — see Primitive for a component-based API.
Features#
triggerProps,popupProps,positionerProps,closeProps, andarrowPropsreturn spread-ready props includingrefcallbacks for each elementstate.openfor conditional rendering of the portal contentsetOpen(open, event)for imperative open/close control- Optional focus trapping with
trappedprop for modal-like behavior
Behavior#
Portal Rendering#
usePopover manages open state and element refs but does not handle DOM portaling. Use usePortal to detect mount state and createPortal from react-dom to render into document.body.
import { usePortal } from '@primereact/headless/portal';
import { createPortal } from 'react-dom';
const portal = usePortal();
{
portal.state.mounted &&
state.open &&
createPortal(
<div {...positionerProps}>
<div {...popupProps}>...</div>
</div>,
document.body
);
}Arrow#
Spread arrowProps on an element inside the popup and pass state.arrowElement to usePositioner. The positioner sets CSS custom properties (--placer-arrow-x, --placer-arrow-y) on the arrow for positioning per side.
const { arrowProps, state } = usePopover();
usePositioner({ anchor: state.anchorElement, content: state.positionerElement, arrow: state.arrowElement });
<div {...popupProps}>
<div {...arrowProps} />
</div>;Style each side using positioner.state.actualSide:
[data-scope='popover'][data-part='arrow'] {
position: absolute;
width: 0.5rem;
height: 0.5rem;
border-left: 1px solid var(--p-content-border-color);
border-top: 1px solid var(--p-content-border-color);
}
[data-part='arrow'][data-side='bottom'] {
top: -0.25rem;
left: var(--placer-arrow-x);
transform: translateX(-50%) rotate(45deg);
}
[data-part='arrow'][data-side='top'] {
bottom: -0.25rem;
left: var(--placer-arrow-x);
transform: translateX(-50%) rotate(225deg);
}Default Open#
Set defaultOpen for uncontrolled popover state.
const popover = usePopover({ defaultOpen: true });Controlled#
Pass open and onOpenChange for controlled usage.
const [isOpen, setIsOpen] = React.useState(false);
const popover = usePopover({
open: isOpen,
onOpenChange: (e) => setIsOpen(e.open)
});Close on Escape#
Set closeOnEscape to close the popover when the Escape key is pressed. Enabled by default.
const popover = usePopover({ closeOnEscape: true });Focus Trapping#
Set trapped to trap focus within the popover content, preventing focus from leaving until the popover is closed.
const popover = usePopover({ trapped: true });When trapped is enabled, render the focus trap sentinels using focusTrap.firstHiddenElementRef and focusTrap.lastHiddenElementRef around the popup content.
Auto Focus#
Set autoFocus to false to prevent automatically focusing the first focusable element when the popover opens.
const popover = usePopover({ autoFocus: false });Custom Styling with Data Attributes#
[data-scope='popover'][data-part='trigger'][data-positioner-open] {
background-color: light-dark(var(--p-surface-100), var(--p-surface-700));
}
[data-scope='popover'][data-part='popup'][data-open] {
opacity: 1;
}API#
usePopover#
| Name | Type | Default |
|---|---|---|
defaultOpen | boolean | undefined |
| Whether the popover is open by default. | ||
open | boolean | undefined |
| Whether the popover is open. | ||
trapped | boolean | false |
| When enabled, focus is trapped within the popover (modal behavior). When disabled, focus leaving the popover closes it (non-modal behavior). | ||
autoFocus | boolean | true |
| Whether to focus the first focusable element when the popover is opened. | ||
closeOnEscape | boolean | true |
| Specifies if pressing escape key should hide the dialog. | ||
onOpenChange | (event: usePopoverOpenChangeEvent) => void | undefined |
| Callback to invoke when the open state changes. | ||
appendTo | "body" | HTMLElement | "self" | 'body' |
| DOM element or CSS selector to append the overlay to. | ||
Accessibility#
See Popover Primitive for WAI-ARIA compliance details and keyboard support.