Search code examples
javascriptiframe

Trigger on a click anywhere else in the document, even with iframes?


So I'm creating a widget that should 'close' if the user clicks anywhere outside of it.

The obvious solution is to put a click handler on the document. That's fine, except that there are other parts of the app that use event.stopPropagation(). So we use the capturing phase in our listener to get around that.

This works for everything, it seems, except for on an iframe. I've made a simple jsfiddle to demonstrate what I'm talking about. A transcript of the code:

var c = document.getElementById('clickme');
var s = document.getElementById('stop');
var t = document.getElementById('text');

document.addEventListener('click', function (event) {
  if (event.target !== c) {
    t.innerHTML += 'outside <br>';
  } else {
    t.innerHTML += 'inside <br>';
  }
}, true); //true to use capturing phase

s.addEventListener('click', function (event) {
  event.stopPropagation();
});

And the setup:

<html>
<body>
  <p>Clicking anywhere but the button counts as an 'outside' click. However, clicks within the iframe do not trigger the event listener.</p>
  <div><button id="clickme">Click me!</button></div>
  <iframe>lalala</iframe>
  <div><button id="stop">Even Me, and I stopPropagation()</button></div>
  <div id="text"></div>
</body>
</html>

Is there any way to make this handler also trigger on clicks within/on the iframe? Also, at the time that I'm attaching the event listener, I won't have a reference to the iframe, so a solution that does not require it would be best.


Solution

  • You can detect a click event within an iframe only if it is on the same domain. See @Tim Down's answer at JavaScript: Detection of a link click inside an iframe

    If the iframe is on another domain, you can take advantage of the fact that a blur event will occur on the document when you click the iframe. You'll need to set a tabIndex on the body element for this to work:

    document.body.tabIndex= 0;
    
    document.addEventListener('blur', function (event) {
      t.innerHTML += 'outside <br>';
    }, true);
    

    Note that multiple clicks within the iframe will trigger only one blur event.

    Fiddle: http://jsfiddle.net/zrgrt9pf/13/