LWC – How to Handle Click Outside Element

I am looking to create a custom lookup component using Lightning Web Components. I want to be able to detect when the user is clicking outside of the element so that I can close the dialog and/or clear the text if nothing is selected. I can't seem to use standard Javascript since template.contains(e.target) and DOM traversal doesn't seem to detect whether the clicked element is inside of the component or not. Here is a sample of what I have attempted.

  1. DOM traversal
let parent = this.template.querySelector('.slds-form-element__row');//parent element
let targetElement = e.target; // clicked element

do {
  if (targetElement == parent) {
    window.console.log('clicked inside');
    return;
  }
  // Go up the DOM
  targetElement = targetElement.parentNode;
} while (targetElement);

window.console.log('clicked outside');
  1. template.contains(e.target)
if (this.template.querySelector('.slds-form-element__row').contains(e.target)) {
  window.console.log('clicked inside');
} else {
  window.console.log('clicked outside');
}

In both of these cases, clicked outside is the only thing I will see since e.target doesn't seem to exist within the DOM element, but I do know my click event (which I've attached to document) is firing since I do see the console.log statement in my developer console.

Best Answer

You can't navigate outside your own template. That's one of the security features of LWC's shadow DOM. Instead, create a transparent, fixed div that covers the entire screen area, then react to that, instead:

<template>
  <div class="backdrop" onclick={closeModal}></div>
  <div class="content">... your content here ...</div>
</template>

.backdrop {
  position: fixed;
  z-index: 999;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
.content {
  z-index: 1000;
  /* anything else you need here */
}

For a complete example, look at Lightning Strike's Lookup component (written in Aura, but still applicable).