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.

Overlay: Events bubbling up to the page can conflict with global shortcuts

See original GitHub issue

via @dusave on slack: Is there a way to stop propagation of Escape when an anchored overlay is open? I just want the anchored overlay to close, but it’s also bubbling up outside of the anchored overlay

Outdated repo (This feature was removed in memex, watch this video instead)

https://github.com/orgs/github/projects/4205/settings/fields/55540

  1. Click on the dates of a given iteration, make the date picker show
  2. Hit Escape
  3. Notice it closes the date picker and settings. We only want it to close the date picker

Update:

Problem:

By default, pressing Escape in an Overlay bubbles up to the page outside the Overlay. Adding event.stopPropagation inside onEscape does not stop the events from bubbling up because of the way the handlers are wired.

const Page = () => {
  React.useEffect(() => {
    // global keydown listener on page.
    document.addEventListener('keydown', console.log('global handler:', event.key))
  }, [])

  return (
    <Overlay
      onEscape={event => {
        closeOverlay()
        // You'd expect this to prevent the event from bubbling 
        // to the global handler on the page, but it doesn't
        event.stopPropogation() 
      }}
    >
      ...
    </Overlay>
  )

Scope

This issue of course isn’t just limited to “Escape”. If an application has global shortcuts, events bubbling out of Overlay can fire global shortcuts.

Why does this happen?

When escape is pressed, you would expect it to be before because Overlay is a child of the Page, but this isn’t the case. Overlay uses the useOnEscapePress hook which attaches an event handler on the document, this is great because no matter where the focus is, pressing Escape will close the top most Overlay.

However, because this event listener is on the document, we cannot predict the order in which it will be fired - will it be before the global handler on the page or after it? And that’s why stopPropagation and preventDefault will not stop the global handler on the Page from catching this event. Here is a loom with a demo of this

There is a repro of this issue in our storybook setup and a failing test in our test suite that would help in finding a fix for this.

Prior work / failed attempts:

We made an attempt to fix this issue in https://github.com/primer/react/pull/1824 by moving the event listener to the Overlay instead of putting it on the document (with container.addEventListener) and adding a event.stopPropagation automatically.

This stopped events from bubbling up, but created a few other bugs:

  1. The Overlay eagerly caught keydown events that were attached to children with onKeyDown inside the Overlay before they fired on the children first. (Story for regression testing)
  2. The Overlay does not catch Escape presses when it is not in focus (which probably a bug anyway?)

Potential fix

After the changes in https://github.com/primer/react/pull/1861, we can attempt to move the event listener back to the Overlay container.

  1. We will have to pair it with adding focus trap on the Overlay, so that focus does not move outside the Overlay and all Escape presses are caught by the Overlay.

  2. Lastly, you should be able to call event.stopPropagation inside a keydown event on a child component inside Overlay (like a TextInput) to prevent the Overlay from closing if Escape is pressed. (Story for testing). If the Overlay is eagerly catching events meant for its children, we can move the event listener to a onKeyDown instead of container.addEventListener. Useful reference to event delegation in React

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
siddharthkpcommented, Jan 17, 2022

This is a bug with Overlay abstraction (not AnchoredOverlay), Added repro with our storybook to the description ⬆️

0reactions
lesliecdubscommented, Aug 29, 2022

No one is actively asking for this right now so we’re going to close for the moment. Let’s reopen if needed.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Event Bubbling and Event Catching in JavaScript and React
In this article, I'll help you understand event bubbling and event catching ... Once an inner child element's event is called, all elements ......
Read more >
Should web pages be restricted from being able to override ...
For the purpose of this bug, the answer is yes, web pages should be able to override all keyboard shortcuts, but only if...
Read more >
Dispatch events - Unity - Manual
Bubbles up : Events sent to elements during the bubble-up phase. ... For a list of dispatch behavior for each event type, see...
Read more >
Is it possible to use bubbling method for document events
The code executes in the order you mentioned, this has nothing to do with event bubbling . document.addEventListener('keydown',closingChat) ...
Read more >
Manage touch events in a ViewGroup - Android Developers
On this page · Intercept touch events in a ViewGroup. Process ACTION_OUTSIDE events · Use ViewConfiguration constants · Extend a child view's ...
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