Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to detect a click outside an element

Short answer

Listen to clicks on the whole document and check with contains() whether the click was inside the element:

<button id="toggle">Menu</button>
<ul id="menu" hidden>
  <li>Profile</li>
  <li>Settings</li>
</ul>
<script>
  const menu = document.getElementById('menu');
  const toggle = document.getElementById('toggle');
 
  toggle.addEventListener('click', () => {
    menu.hidden = !menu.hidden;
  });
 
  document.addEventListener('click', (event) => {
    if (!menu.contains(event.target) && !toggle.contains(event.target)) {
      menu.hidden = true;
    }
  });
</script>

With closest

closest() finds the nearest parent that matches a selector. It is handy when there are several dropdowns:

document.addEventListener('click', (event) => {
  if (!event.target.closest('.dropdown')) {
    document.querySelectorAll('.dropdown.open').forEach((el) => el.classList.remove('open'));
  }
});

The Escape key

Users expect a popup to close on Escape too:

document.addEventListener('keydown', (event) => {
  if (event.key === 'Escape') menu.hidden = true;
});

Common mistake

Without the check for the button, a click on the button opens the menu, and the same click reaches the document and closes it at once. Exclude the button or stop the event with event.stopPropagation().

toggle.addEventListener('click', (event) => {
  event.stopPropagation();
  menu.hidden = !menu.hidden;
});

Thanks for reading!

Donate to the site — we work hard for you.