Skip to main content
Kaleidoscope

Nested Portals

Open Popovers, OptionMenus, and other portalled components from within other portalled components without losing focus.

Background

When you render a portalled component (like a Popover or OptionMenu) inside another portalled component, the inner component renders in a separate DOM node via a React portal. This can cause the outer component to lose focus and close unexpectedly, since the inner component's DOM is outside the outer component's focus trap.

The nested portal pattern solves this by:

  1. Marking the inner component with className="nested-portal" so the outer component knows not to close when focus moves into it
  2. Manually controlling the outer component's focus trap when needed

Using className="nested-portal"

For simple cases — like a Popover or OptionMenu rendered inside another Popover — adding className="nested-portal" to the inner component is all you need.

Editable example

Nested portals inside OptionMenu

When rendering a portalled component inside an OptionMenu, you need to also manage the OptionMenu's focus trap. Use OptionMenuNestedPortalConsumer to get access to focus trap controls, and toggle them when the nested component opens and closes.

Editable example

Key points for OptionMenu nesting:

  • Wrap the nested component in OptionMenuNestedPortalConsumer to access the focus trap context
  • Call context.deactivateFocusTrap() when the nested component opens
  • Call context.activateFocusTrap() when the nested component closes
  • Set closeOnClick={false} on the trigger OptionMenuItem to prevent the menu from closing when the nested component is activated

Nested OptionMenu inside another portalled component

You can also nest an OptionMenu inside a Popover or other portalled component. The same className="nested-portal" pattern applies.

Editable example

Summary

ScenarioWhat you need
Portalled component inside a PopoverAdd className="nested-portal" to the inner component
Portalled component inside an OptionMenuAdd className="nested-portal" + use OptionMenuNestedPortalConsumer to manage the focus trap
OptionMenu inside a PopoverAdd className="nested-portal" to the OptionMenu