PrimeReact 11.1.0 landed on 5 August 2026. It is a small release and most of it is a single fix, in the overlay components, for a bug that comes out of portals and event ordering. That combination catches people out often enough that the fix is most of this post.

npm install [email protected]

It needs React 19, same as 11.0.

Clicking inside an overlay could close it

Select, AutoComplete, DatePicker, Menu, ContextMenu and Popover all render their panel through a portal. The panel is a child of document.body, not of the component that owns it.

Those components also dismiss on outside clicks, which means a listener on document. In usePopover that listener is bound on pointerdown with useEventListener, whose target defaults to document. It asks whether the event landed inside the overlay, and closes it when the answer is no.

The containment check is where the portal causes trouble. In the DOM, a portaled panel is not inside the component’s element, so checking the anchor and the positioner for the click target says the click was outside. React hides this in its own synthetic event system, where events bubble through the React tree rather than the DOM tree, and a synthetic handler on the panel does fire.

The synthetic handler is not much help here, because React attaches its listeners at the root container. By the time the synthetic handler on the panel runs, the document listener has already fired and already decided to close, so the panel closes underneath the click that was meant for it.

The case that made this visible was a Select opened inside a Popover. The Select’s own panel is portaled to the body, so as far as the Popover was concerned a click on an option happened somewhere else entirely, and the Popover dismissed itself along with the Select inside it.

How useOverlayClickEmitter closes the race

11.1.0 adds useOverlayClickEmitter in @primereact/core/utils, used by all six popup components. Its own documentation describes the problem exactly:

Bound natively in the capture phase: a React synthetic handler on a portaled popup runs after the document-level listener that consumers (see usePopover) dismiss on, and would lose that race.

Two decisions in that sentence carry the fix. The listener is native rather than a React one, so it runs in the same system as the dismiss logic, and it binds in the capture phase on the popup element itself, which puts the overlay’s announcement ahead of the bubble-phase listener at document level.

The signature is small:

useOverlayClickEmitter(
    popupElement: HTMLElement | null | undefined,
    getTarget: () => Element | null | undefined,
): void

The popup element is tracked in state rather than a ref, so the effect re-runs when the panel mounts. getTarget reports which element owns the overlay, and with that the dismiss check on the owner can recognise an interaction that happened in a panel somewhere else in the DOM. The emitter listens for pointerdown only, and the reason for that is in the source: a second emit per interaction leaves an unconsumed self-click flag behind, and that flag then swallows the next genuine outside click. The event it publishes on OverlayEventBus is overlay-click, and usePopover consumes it by setting a self-click flag that its own dismiss handler reads and clears.

That clearing is the second half of the fix. The flag describes the current interaction and nothing more, so it is read and reset on every interaction now rather than only when it was set. If it stays set, the next outside click reads a flag left over from an earlier interaction and does nothing, which is how a stale flag used to turn into a dismiss that never happened.

Ownership across the portal

The emitter alone is not enough for overlays nested inside overlays. For that case 11.1.0 adds overlayOwner, which links a portaled popup back to the anchor that opened it, using a data-overlay-owner attribute plus a property holding the anchor element itself. It holds an element reference and not an id, so nothing needs generating and the link cannot point at something that has gone away.

usePopover then walks that chain. Its new ownsNode helper checks the positioner and the anchor first, and when the node is in neither, climbs the owner chain hop by hop to see whether it eventually lands back inside this overlay. Both the outside-click check and the focus-out check go through it, so “focus moved into a nested overlay of mine” and “focus left entirely” are two different answers now instead of one.

If you have built your own portaled overlay on top of PrimeReact’s primitives and you have been fighting the same race, useOverlayClickEmitter and overlayOwner are the two pieces to reach for.

Sidebar got tree-style keyboard navigation, which is a bigger change than the name suggests. The menu handles arrow keys, Home and End, and left and right collapse and expand a branch. New prop getters and types come with it, so have a look at those if you drive Sidebar from headless.

PrimeReactProvider takes a locales prop, so several languages can be registered in one place instead of swapping a single locale object at runtime.

There is also a new useEscapeListener hook. Escape handling used to be one listener per component and is now a dismiss stack. The topmost layer wins, and a layer with closeOnEscape: false swallows the key instead of passing it down, so one press on a dialog with a popover open behind it closes the dialog only. Dialog and Popover both went through the new hook.

Two fixes in core: the defaults config no longer drops props a component does not declare, and locale registration no longer depends on import order or misses on first render.

If you import from @primereact/core/utils directly, note that ConnectedOverlayScrollHandler is gone. It was deleted along with its export in the same commit as the overlay fix.

If you are on 11.0 and any of those six components sit inside a portal-heavy layout, this is the upgrade to take.