MiHCM
overlay/@mihcm/ui·v0.21.0·stable

Popper

Low-level Popper.js v2 positioning primitive for custom floating panels, virtual anchors, arrows, portals, and modifiers.

Accessibility

Popper is a positioning primitive. It handles geometry, not complete widget semantics.

Defaults

  • PopperTrigger sets aria-expanded and aria-haspopup="dialog".
  • PopperContent renders role="dialog" by default.
  • Escape closes the layer and returns focus to the trigger.
  • Outside pointer down closes uncontrolled and controlled layers through onOpenChange(false).
  • With portalled enabled, PopperContent renders in document.body through React DOM createPortal.

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, and role="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.