question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[MDCMenuSurface] Unable to toggle MenuSurface closed due to 'greedy' body click handler

See original GitHub issue

Bug report

I’ve been trying to create an app bar with a button to toggle a menu, a bit like this:

image

I tried to achieve this by implementing a ‘naive’ click handler on my toggle button:

toggle.addEventListener('click', () => menu.open = !menu.open);

This works to open the menu, however once the menu is open and the toggle is clicked to close it, the menu closes and then rapidly reopens again. I’ve done some digging and tracked it down to the way that MDCMenuSurface listens for clicks on body to close the menu when the user clicks away:

https://github.com/material-components/material-components-web/blob/7313fc1a7d6dd4fec142d6392f97c6847d46519a/packages/mdc-menu-surface/component.ts#L70-L75

Thanks to the {capture: true} on body, this handler will always be triggered first and close the menu. Then when the event continues on down to my ‘naive’ toggle handler, it ends up reopening the menu.

I’ve created a ‘dirty’ workaround, which stops the event from propagating any further down the DOM so that my handler isn’t run, which is really not ideal:

toggle.addEventListener('click', () => {
  menu.open = !menu.open
  // Stop the click event from reaching the toggle element so that the toggle click handler
  // isn't run. The menu will be closed first by the handler registered in the MCDMenuSurface component
  document.body.addEventListener(
    'click', e => e.stopPropagation(),
    {capture: true, once: true}
  );
});

Here is my demo showing both behaviours: https://codepen.io/dabrowne/pen/zYrWzxd

There needs to be an easier way to achieve what I would assume is quite common functionality. Have I missed something? Am I doing it wrong?

Your Environment:

Software Version(s)
MDC Web 7.0.0
Browser Firefox
Operating System Windows 10, Ubuntu 18

Possible solution

It would be great if we could remove the {capture: true} so that MCDMenuSurface isn’t so greedy with it’s event capture, but there’s an existing comment there rationalizing it to fix a race condition (I tried tracing the code but couldn’t find the race myself).

Even better would be if we could register the ‘toggle’ element with the MDCMenu or MDCMenuSurface component, and the component itself can be in charge of open/close on element click.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:5
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

3reactions
sb8244commented, Dec 7, 2020

One bug I noticed with the workaround: It opens the menu, but then the first click is ignored because the click never made it to the body. I have no clue what would cause this, but it goes away when I remove the handler.

I changed it to the following (with a reference to my button element in scope):

        document.body.addEventListener('click', (e) => {
          if (buttonEl.contains(e.target)) {
            e.stopPropagation()
          }
        }, { capture: true, once: true })
1reaction
EstebanG23commented, Jul 17, 2020

Hi there, thanks for raising this issue. I was able to reproduce with the steps provided. Adding to backlog.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Menu Surface - Material Design
The MDC Menu Surface component is a reusable surface that appears above the content of the page and can be positioned adjacent to...
Read more >
Material Design Web 1.0 and mdc-menu-surface--anchor how ...
I am not sure if this is the best solution, but for the moment I solved this in the following way: <html lang="en">...
Read more >
MDCMenuSurfaceFoundation | material-components-web
Handle clicks and close if not within menu-surface element. Parameters. evt: MouseEvent. Returns void. handleKeydown. handleKeydown ...
Read more >
ember-cli-mdc-menu-surface - npm
ember-cli addon for @material/menu-surface.. Latest version: 3.0.0-alpha.21, last published: 3 months ago.
Read more >
Modular and customizable Material Design UI components for ...
Material Components for the web helps developers execute Material Design. ... to prevent mdc-menu-surface from closing with outside clicks ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found