Skip to content

fix(ContextualMenu): don't close on clicks inside portalled content - #1449

Open
joydaven wants to merge 1 commit into
canonical:mainfrom
joydaven:fix/contextual-menu-portal-click
Open

joydaven wants to merge 1 commit into
canonical:mainfrom
joydaven:fix/contextual-menu-portal-click

Conversation

@joydaven

@joydaven joydaven commented Oct 19, 2026 •

Copy link
Copy Markdown

Done

  • ContextualMenu no longer closes when the user clicks inside content that the menu renders but that is portalled elsewhere in the DOM, such as a Modal or ConfirmationButton opened from a menu item. Previously the click counted as "outside", the menu closed and the modal unmounted with it, so projects were disabling closeOnOutsideClick altogether.
  • Outside-click handling moves from usePortal's DOM contains check into the component. A capture handler on the wrapper records mousedowns that start anywhere in the menu's React tree (React events bubble through portals, so this includes the dropdown and anything portalled out of it), and a document listener ignores that event. Nothing is coupled to Modal. Existing behaviour is unchanged: outside clicks close the menu, closeOnOutsideClick={false} disables that, and only the main button counts.
  • Added an "Opens a modal" story and six tests: outside click, click inside the dropdown, click inside a portalled child, a confirmation modal opened from the menu, the disabled flag, and non-main buttons. The two portal tests fail on main.

Before / after


https://www.loom.com/share/f92a9293633b4b60b76ba7dc60f465aa

Before: clicking inside the confirmation modal closes the menu and the modal with it. After: both stay open until the user cancels or clicks outside.

QA

Pinging @canonical/react-library-maintainers for a review.

QA steps

  • Run yarn docs, open ContextualMenu -> Opens a modal.
  • Click "Actions", then "Delete", then click the modal's body text. The modal and the menu stay open. "Cancel" closes the modal; clicking elsewhere closes the menu.
  • Check the existing ContextualMenu stories still close on an outside click and on Escape.

Testing

  • yarn lint and tsc --noEmit: clean.
  • jest src/components/ContextualMenu: 57 tests pass. With the component change stashed, the two new portal tests fail as expected.

Percy steps

One new snapshot for the ContextualMenu "Opens a modal" story (menu closed). No changes to existing stories expected.

Fixes

Fixes: #1049

Content opened from a menu item, such as a Modal or ConfirmationButton, is rendered through a portal and so is not a DOM descendant of the menu. usePortal's outside-click check therefore treated clicks inside it as outside, closed the menu and unmounted the modal with it. Handle outside clicks in the component instead: a capture handler on the wrapper records any mousedown that starts inside the menu's React tree (React events bubble through portals), and the document listener ignores that event. Outside clicks, closeOnOutsideClick={false} and the main-button-only rule behave as before. Fixes canonical#1049

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ContextualMenu: outside click should be ignored if there is a modal open

1 participant