How do I detect a click outside an element? How do I detect a click outside an element? javascript javascript

How do I detect a click outside an element?


Note: Using stopPropagation is something that should be avoided as it breaks normal event flow in the DOM. See this CSS Tricks article for more information. Consider using this method instead.

Attach a click event to the document body which closes the window. Attach a separate click event to the container which stops propagation to the document body.

$(window).click(function() {  //Hide the menus if visible});$('#menucontainer').click(function(event){  event.stopPropagation();});


You can listen for a click event on document and then make sure #menucontainer is not an ancestor or the target of the clicked element by using .closest().

If it is not, then the clicked element is outside of the #menucontainer and you can safely hide it.

$(document).click(function(event) {   var $target = $(event.target);  if(!$target.closest('#menucontainer').length &&   $('#menucontainer').is(":visible")) {    $('#menucontainer').hide();  }        });

Edit – 2017-06-23

You can also clean up after the event listener if you plan to dismiss the menu and want to stop listening for events. This function will clean up only the newly created listener, preserving any other click listeners on document. With ES2015 syntax:

export function hideOnClickOutside(selector) {  const outsideClickListener = (event) => {    const $target = $(event.target);    if (!$target.closest(selector).length && $(selector).is(':visible')) {        $(selector).hide();        removeClickListener();    }  }  const removeClickListener = () => {    document.removeEventListener('click', outsideClickListener)  }  document.addEventListener('click', outsideClickListener)}

Edit – 2018-03-11

For those who don't want to use jQuery. Here's the above code in plain vanillaJS (ECMAScript6).

function hideOnClickOutside(element) {    const outsideClickListener = event => {        if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null          element.style.display = 'none'          removeClickListener()        }    }    const removeClickListener = () => {        document.removeEventListener('click', outsideClickListener)    }    document.addEventListener('click', outsideClickListener)}const isVisible = elem => !!elem && !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ) // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js 

NOTE:This is based on Alex comment to just use !element.contains(event.target) instead of the jQuery part.

But element.closest() is now also available in all major browsers (the W3C version differs a bit from the jQuery one).Polyfills can be found here: Element.closest()

Edit – 2020-05-21

In the case where you want the user to be able to click-and-drag inside the element, then release the mouse outside the element, without closing the element:

      ...      let lastMouseDownX = 0;      let lastMouseDownY = 0;      let lastMouseDownWasOutside = false;      const mouseDownListener = (event: MouseEvent) => {        lastMouseDownX = event.offsetX        lastMouseDownY = event.offsetY        lastMouseDownWasOutside = !$(event.target).closest(element).length      }      document.addEventListener('mousedown', mouseDownListener);

And in outsideClickListener:

const outsideClickListener = event => {        const deltaX = event.offsetX - lastMouseDownX        const deltaY = event.offsetY - lastMouseDownY        const distSq = (deltaX * deltaX) + (deltaY * deltaY)        const isDrag = distSq > 3        const isDragException = isDrag && !lastMouseDownWasOutside        if (!element.contains(event.target) && isVisible(element) && !isDragException) { // or use: event.target.closest(selector) === null          element.style.display = 'none'          removeClickListener()          document.removeEventListener('mousedown', mouseDownListener); // Or add this line to removeClickListener()        }    }


How to detect a click outside an element?

The reason that this question is so popular and has so many answers is that it is deceptively complex. After almost eight years and dozens of answers, I am genuinely surprised to see how little care has been given to accessibility.

I would like to hide these elements when the user clicks outside the menus' area.

This is a noble cause and is the actual issue. The title of the question—which is what most answers appear to attempt to address—contains an unfortunate red herring.

Hint: it's the word "click"!

You don't actually want to bind click handlers.

If you're binding click handlers to close the dialog, you've already failed. The reason you've failed is that not everyone triggers click events. Users not using a mouse will be able to escape your dialog (and your pop-up menu is arguably a type of dialog) by pressing Tab, and they then won't be able to read the content behind the dialog without subsequently triggering a click event.

So let's rephrase the question.

How does one close a dialog when a user is finished with it?

This is the goal. Unfortunately, now we need to bind the userisfinishedwiththedialog event, and that binding isn't so straightforward.

So how can we detect that a user has finished using a dialog?

focusout event

A good start is to determine if focus has left the dialog.

Hint: be careful with the blur event, blur doesn't propagate if the event was bound to the bubbling phase!

jQuery's focusout will do just fine. If you can't use jQuery, then you can use blur during the capturing phase:

element.addEventListener('blur', ..., true);//                       use capture: ^^^^

Also, for many dialogs you'll need to allow the container to gain focus. Add tabindex="-1" to allow the dialog to receive focus dynamically without otherwise interrupting the tabbing flow.

$('a').on('click', function () {  $(this.hash).toggleClass('active').focus();});$('div').on('focusout', function () {  $(this).removeClass('active');});
div {  display: none;}.active {  display: block;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><a href="#example">Example</a><div id="example" tabindex="-1">  Lorem ipsum <a href="http://example.com">dolor</a> sit amet.</div>