This has to do with how events work in JavaScript.
Let's say you have this HTML:
<div id="content">
<input type="button />
</div>
If you click the button, a click event is generated. The event will start in the capturing phase (top down), it will go down starting at window
, then div#content
then the button. Then the bubbling phase starts (bottom up), first the button, then div#content
then window
.
Events attach to the bubbling phase by default so your button receives the click event, shows the popup, then the window receives the click and hides the popup. That's a little inconvenient.
One way to get around this is to use stopPropagation
to stop the event from bubbling up. This approach has some issues. For instance if you have 2 buttons that can produce a popup. Clicking button1 then button2 will not close the first popup because the shared parent never sees any of the click events.
Another solution is to add the popup close in the capture phase instead. A potential problem here surfaces when you want to block clicks on the popup itself from closing the popup. This block is difficult to determine in the capture phase. An additional solution is to mark the event in the capture phase, and delay closing to the bubble phase (allowing the popup to throw a block). This does not play nice with stopPropagation
however. Any element with stopPropagation
will cause the popup closer to fail because the event will never bubble up again.
Another way is to let the popup handler know it should ignore the next click. stopPropagation
again has the potential to do damage here. For instance when id#content
has stopPropagation
on it.
You could also use some kind of setTimeout
trick to delay rendering of the popup until the click event has finished it's bubble phase. This works but it feels like a terrible hack.
As you can see from this fairly elaborate answer, this is a problem I've run into myself and have put quite a bit of thought into. I don't know the solution yet. Every solution seems to have it's problems. I have decided however that stopPropagation
is bad. My reasoning is that stopPropagation
breaks modularity. A child node can affect the behavior of a parent node without the parent's consent or knowledge, this seems like a problem.