I built a web component with lit-element and Typescript. It includes a dropdown that I'd like to close if the user clicks anywhere else on the page. Having a global click-listener is simple:
window.addEventListener('click', e => this.globalClickHandler(e), false)
But inside the globalClickHandler
I need to differentiate between clicks inside my component and outside of it - how can I achieve that? I can't use event-target
because it would just give me the top-most shadow root.
I hope this helps someone because it literally took me hours to find out.
globalClickHandler(event) {
if (!event.composedPath().includes(this)) {
// this.open = false or whatever floats your boat
}
}
Normally you would do something like this.contains(event.target)
but that won't work for us because our EventTarget isn't the actual element that was clicked and our this
's only child is a ShadowRoot. Luckily event.composedPath()
was created to mitigate this:
The composedPath() method of the Event interface returns the event’s path which is an array of the objects on which listeners will be invoked.
So composedPath is basically a list of all the elements our event traveled through while ignoring the shadow DOMs on its way. This means all we have to do is go through the array of elements we get and check if our element (this
) is included.