How to close popup by clicking outside with JavaScript

I’ve created a popup when a button is clicked in vanilla JavaScript. But I wanted to create a way where I can make the popup close when a user clicks outside the popup but keep the popup visible when clicked inside. Is that possible?

Here’s some code that creates the output above:


<button id="popup-trigger">Click for popup</button>

<div id="popup">
  Click outisde the box to close
</div>
<style>
  body {
    text-align: center;
    padding-top: 50px;
  }
  #popup {
    position: absolute;
    top: 90px;
    right: 0;
    left: 0;
    box-shadow: 0px 3px 3px -2px rgba(0, 0, 0, 0.2),
      0px 3px 4px 0px rgba(0, 0, 0, 0.14),
      0px 1px 8px 0px rgba(0, 0, 0, 0.12);
    width: 250px;
    margin: auto;
    z-index: 3;
    overflow: hidden;
    border-radius: 4px;
    display: none;
    padding: 8px;
    text-align: center;
  }
  #popup.show {
    display: block;
  }
</style>
<script>
  const popupQuerySelector = "#popup";
  const popupEl = document.querySelector(popupQuerySelector);
  const popupBttn = document.querySelector("#popup-trigger");

  popupBttn.addEventListener("click", () => {
    setTimeout(() => {
      if (!popupEl.classList.contains("show")) {
        // Add class `show` to filterList element
        popupEl.classList.add("show");
      }
    }, 250);
  });
</script>

Pretty basic code. Now let’s get to the solution on how to close a popup when clicked outside the element.

Solution: use Element.closest() inside a document click event listener

Element.closest() works its way to the top of the root of the DOM object to see if it can find a match for the query selector that was provided.


const isClosest = e.target.closest(popupQuerySelector);

If Element.closest() finds the match, it will return the element otherwise it will return null.

Now that I know that’s the tool I want to use, I need to attach it the document with addEventListener(). Let’s see how this put into practice:


document.addEventListener("click", (e) => {
  // Check if the filter list parent element exist
  const isClosest = e.target.closest(popupQuerySelector);

  // If `isClosest` equals falsy & popup has the class `show`
  // then hide the popup
  if (!isClosest && popupEl.classList.contains("show")) {
    popupEl.classList.remove("show");
  }
});

Let’s do a code breakdown. The first step is to create attach a click event listener to the document.

I want to do this because I want to capture everything in the page to make sure the user is click outside the popup element.

The next line of code is using closest(), and underneath that line I’m performing a IF condition to see if closest() returned null & if the popup element currently has the class .show , if so hide the popup!

I like to tweet about JavaScript and post helpful code snippets. Follow me there if you would like some too!