Accessibility
Popper is a positioning primitive. It handles geometry, not complete widget semantics.
Defaults
PopperTriggersetsaria-expandedandaria-haspopup="dialog".PopperContentrendersrole="dialog"by default.Escapecloses the layer and returns focus to the trigger.- Outside pointer down closes uncontrolled and controlled layers through
onOpenChange(false). - With
portalledenabled,PopperContentrenders indocument.bodythrough React DOMcreatePortal.
Portal notes
- A portal changes physical DOM placement only. React context, state ownership, and event bubbling still follow the React tree.
- Portal rendering avoids clipping from
overflow, transforms, and nested stacking contexts, but it does not create a modal focus trap. - If a parent React click handler closes the layer unexpectedly, handle propagation intentionally inside the portalled content.
- Use
portalled={false}only for contained previews, embedded widgets, or cases where the local stacking context is required.
Required by consumers
- Pick the correct semantic pattern for the final widget. Use
role="menu"for menus,role="listbox"for custom selects, androle="tooltip"for non-interactive descriptions. - Manage roving focus or active descendant behavior when building composite widgets.
- Keep all interactive children keyboard reachable.
- Provide visible focus states using design-system focus tokens.
- Do not use Popper for modal flows. Use Dialog or Sheet when focus must be trapped.
Security
- Do not render model-generated or user-generated HTML inside
PopperContent. - Validate any data used to build custom modifiers. Modifiers execute during layout and can mutate DOM attributes/styles.
- Keep portal usage enabled when clipping could hide security-relevant controls such as destructive action confirmations.