Avoid event capturing by another application

Simply speaking, I have something like this

// Adds listener to capturing phase
document.addEventListener('focusin', event => event.stopPropagation(), true); 

document.querySelector('#my_div')
    .addEventListener('focusin', event => console.log('my logic'));

First event listener comes from the the application which I have no control over. It blocks all the focuses on the capturing phase (and it’s also doing some logic which I omitted for the simplicity) and focuses on the modal window.

I embed my application (it’s a content script of the Chrome extension) on the page and want to focus on the input of my ebedded element. It’s not possible since all focusin event are captured by first element listener and it’s not propagating it down to my element.

Is there any workaround to this problem? Note that I can’t just fix the first listener since I have no control over this… Any ideas (and dirty hacks 🙂 are highly appreciated.

Answer

Problem

Your focusin listener is registered in the default second phase (“bubbling”) since you didn’t specify true. The site’s focusin listener is registered with true in addEventListener so it runs in the first “capturing” phase (when the event descends from window to document and down to the focused element) and by using stopPropagation it stops further dispatching of the event so it never even reaches the default second phase where your listener waits.

Solution

As described above, the event in the capturing phase descends from window, so we can register a capturing listener on window to make it run before the site’s document listener:

window.addEventListener('focusin', e => {
  // For nested inputs the condition should be e.target.closest('#my_div')
  if (e.target.id === 'my_div') {
    console.log('my logic');
  }
}, true);