By Sergio del Amo


2008-09-30 13:17:12 8 Comments

I have some HTML menus, which I show completely when a user clicks on the head of these menus. I would like to hide these elements when the user clicks outside the menus' area.

Is something like this possible with jQuery?

$("#menuscontainer").clickOutsideThisElement(function() {
    // Hide the menus
});

30 comments

@Rivenfall 2019-06-25 15:23:25

First you have to track wether the mouse is inside or outside your element1, using the mouseenter and mouseleave events. Then you can create an element2 which covers the whole screen to detect any clicks, and react accordingly depending on wether you are inside or outside element1.

I strongly recommend to handle both initialization and cleanup, and that the element2 is made as temporary as possible, for obvious reasons.

In the example below, the overlay is an element positionned somewhere, which can be selected by clicking inside, and unselected by clicking outside. The _init and _release methods are called as part of an automatic initialisation/cleanup process. The class inherits from a ClickOverlay which has an inner and outerElement, don't worry about it. I used outerElement.parentNode.appendChild to avoid conflicts.

import ClickOverlay from './ClickOverlay.js'

/* CSS */
// .unselect-helper {
//  position: fixed; left: -100vw; top: -100vh;
//  width: 200vw; height: 200vh;
// }
// .selected {outline: 1px solid black}

export default class ResizeOverlay extends ClickOverlay {
    _init(_opts) {
        this.enterListener = () => this.onEnter()
        this.innerElement.addEventListener('mouseenter', this.enterListener)
        this.leaveListener = () => this.onLeave()
        this.innerElement.addEventListener('mouseleave', this.leaveListener)
        this.selectListener = () => {
            if (this.unselectHelper)
                return
            this.unselectHelper = document.createElement('div')
            this.unselectHelper.classList.add('unselect-helper')
            this.unselectListener = () => {
                if (this.mouseInside)
                    return
                this.clearUnselectHelper()
                this.onUnselect()
            }
            this.unselectHelper.addEventListener('pointerdown'
                , this.unselectListener)
            this.outerElement.parentNode.appendChild(this.unselectHelper)
            this.onSelect()
        }
        this.innerElement.addEventListener('pointerup', this.selectListener)
    }

    _release() {
        this.innerElement.removeEventListener('mouseenter', this.enterListener)
        this.innerElement.removeEventListener('mouseleave', this.leaveListener)
        this.innerElement.removeEventListener('pointerup', this.selectListener)
        this.clearUnselectHelper()
    }

    clearUnselectHelper() {
        if (!this.unselectHelper)
            return
        this.unselectHelper.removeEventListener('pointerdown'
            , this.unselectListener)
        this.unselectHelper.remove()
        delete this.unselectListener
        delete this.unselectHelper
    }

    onEnter() {
        this.mouseInside = true
    }

    onLeave() {
        delete this.mouseInside
    }

    onSelect() {
        this.innerElement.classList.add('selected')
    }

    onUnselect() {
        this.innerElement.classList.remove('selected')
    }
}

@Yair Cohen 2019-02-11 14:47:00

Let's say the div you want to detect if the user clicked outside or inside has an id, for example: "my-special-widget".

Listen to body click events:

document.body.addEventListener('click', (e) => {
    if (isInsideMySpecialWidget(e.target, "my-special-widget")) {
        console.log("user clicked INSIDE the widget");
    }
    console.log("user clicked OUTSIDE the widget");
});

function isInsideMySpecialWidget(elem, mySpecialWidgetId){
    while (elem.parentElement) {
        if (elem.id === mySpecialWidgetId) {
            return true;
        }
        elem = elem.parentElement;
    }
    return false;
}

In this case, you won't break the normal flow of click on some element in your page, since you are not using the "stopPropagation" method.

@Art 2010-06-12 08:35:55

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) { 
  $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) => {
    $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: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

@Eran Galperin 2010-06-16 20:14:47

While your method works as well, your statement is completely erroneous. #menucontainer is the bottom level in the propagation chain for all the elements it contains, therefor it doesn't change any of its behavior. You should try it and see for yourself.

@Pistos 2012-04-05 19:30:02

I tried many of the other answers, but only this one worked. Thanks. The code I ended up using was this: $(document).click( function(event) { if( $(event.target).closest('.window').length == 0 ) { $('.window').fadeOut('fast'); } } );

@umassthrower 2012-04-07 23:41:56

I actually ended up going with this solution because it better supports multiple menus on the same page where clicking on a second menu while a first is open will leave the first open in the stopPropagation solution.

@jsgroove 2012-12-04 15:19:00

This is a very good solution for multiple items on the page.

@John 2013-05-08 15:23:01

Excellent answer. This is the way to go when you have multiple items which you wish to close.

@developer.ejay 2014-04-25 02:45:33

This should be the accepted answer because of the flaw the other solution has with event.stopPropagation().

@Bruce 2014-05-29 00:02:20

This should be the accepted answer, for more detailed answer refer to this page: css-tricks.com/dangers-stopping-event-propagation

@Bohdan Lyzanets 2014-07-24 09:32:01

as variant: var $menu = $('#menucontainer'); $(document).on('click', function (e) { // if element is opened and click target is outside it, // close it if ($menu.is(':visible') && !$menu.is(e.target) && !$menu.has(e.target).length) { $menu.hide(); } });

@James Heston 2014-09-14 17:05:39

This is a better solution than any that use $('html').stopPropagation(), as those are very likely to interfere the functionality of other parts of site. I would hope someone will mark this as the answer instead.

@vsync 2014-11-18 13:31:51

One line example - !$(e.target).closest('.menu').length && $('.menu').is(":visible") && $('.menu').hide();

@ncubica 2014-11-21 00:45:22

why no body has checked for tagName var $target = $(event.target); if($target.get(0).tagName.toUpperCase() === "BODY"){ console.log("you click the body"); }

@AliBZ 2015-02-23 22:56:07

closest doesn't work for dynamically loaded elements (like items loaded by backbone.marionettejs's CollectionView).

@BadHorsie 2015-03-12 13:35:51

This didn't work for me when there was only one element on the page. If I had multiple elements on the page it worked fine.

@ProblemsOfSumit 2015-06-13 13:23:21

much much better, especially with web apps that hijack internal link behaviour for HTML5 History API use. (so, all of them)

@Alex Ross 2015-07-31 01:56:15

Without jQuery - !element.contains(event.target) using Node.contains()

@pablito.aven 2015-08-20 14:37:37

This is absolutely best choice in my opinion. Stopping event propagation is very messy if the div you want to hide has something cilckable inside it.

@Wallace Maxters 2015-09-21 19:50:42

I make so: $(event.target).closest('#menucontainer').size() == 0

@Craig Jacobs 2015-11-23 21:16:02

For responsive designs rather than click use on like this: $(document).on('touchstart click', function(event){...

@ColdTuna 2016-01-07 14:07:58

This works great, however, sometimes $(event.target) comes as an empty string... any idea why? I am clicking on the same target every time.

@Bjørn Stenfeldt 2016-02-08 07:50:21

"The .closest() method begins its search with the element itself before progressing up the DOM tree" - api.jquery.com/closest. So it should be possible to remove ` && !$(event.target).is('#menucontainer')`.

@Bjørn Stenfeldt 2016-02-08 08:32:27

I had 2 document click events because 2 containers needed to close separately when clicked outside of them. This actually gave me some problems, because clicking the link to open the second container wouldn't close the first and vice versa. But separately they worked fine. The fix turned out to be the mouseup event instead of the click event on document.

@Ryan Little 2016-02-09 00:10:11

This seems to work but not on mobile, can this be confirmed?

@Khalid T. 2016-02-23 13:46:13

I agree with @Bjørn Stenfeldt. There is no need for the !$(event.target).is('#menucontainer') part when using .closest()

@Sprose 2016-06-06 09:41:06

Fantastic solution and works great. I just adapted the $('#menucontainer').hide(); section to $('#menucontainer').removeClass('showMenu'); to work with my all products menu.

@bdb.jack 2017-01-17 16:28:10

I'm promoting this because it has the !$(event.target).closest('#element').length check, which was exactly what i needed in my own application.

@markthewizard1234 2017-04-07 10:05:12

This is the perfect solution - it does what it needs to do without breaking other elements within the container. I had an issue where Ajax links were not working with the stopPropagation().

@Chris Chalmers 2017-07-28 23:49:53

works like a charm! I used .parents() instead of .closest() because my elements have multiple levels inside.

@David Yeiser 2018-03-01 17:37:15

Has anyone gotten this to work on mobile devices?

@Robert Munn 2019-03-19 15:00:22

If you want to limit this function to just detecting the click but not acting on it, you can wrap the entire function in a Promise, remove hiding the element, and resolve the promise after calling removeEventListener. You can use .then(...) to act on detecting the click from where you called this function. Better encapsulation, more clear in source what is happening.

@Shmalex 2019-04-01 18:03:31

thank you for your solution. It works great. But I noticed when I add this handler during another click event - the listener get called during of the event bubbling phase. To fix that problem I came up with solution like setTimeout((x)=>{ document.addEventListener('click', outsideClickListener);},1);

@Eran Galperin 2008-09-30 13:38:11

NOTE: Using stopEventPropagation() is something that should be avoided as it breaks normal event flow in the DOM. See this 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();
});

@vsync 2009-08-17 16:47:39

I prefer to bind the document to the click event, then unbind the event when needed. its more efficient.

@Art 2010-06-12 08:00:10

This breaks standard behaviour of many things, including buttons and links, contained within #menucontainer. I am surprised this answer is so popular.

@Art 2010-06-12 08:38:16

I have posted an alternative solution, which does not break he behaviour stackoverflow.com/questions/152975/…

@Eran Galperin 2010-06-16 19:55:20

This doesn't break behavior of anything inside #menucontainer, since it is at the bottom of the propagation chain for anything inside of it.

@meo 2011-02-25 15:35:29

its very beautyfull but you should use $('html').click() not body. The body always has the height of its content. It there is not a lot of content or the screen is very high, it only works on the part filled by the body.

@Frederik Wordenskjold 2011-03-19 02:43:24

meo + 1. Should be html instead of body. Same argument for horizontal space; if a page has fluid margins, and the monitor is wider than the content, the menu will not hide when clicking outside of the area if you use body.

@Mathias Bynens 2011-09-27 12:18:39

@medo It should really be $(document).

@Prusprus 2011-11-18 15:59:19

@Art a simple workaround for this would be to stop the propagation the wrapper div that contains the content for the menu.

@tundoopani 2011-12-31 06:00:18

@user751564 how would we do that? Nest another div with the content inside #menucontainer?

@umassthrower 2012-04-07 23:22:33

Evan, Sergio, Joe, Art, meo, and everyone else (+Joel & Jeff) I love you all. It would have taken me a day to eventually get around to realizing event.stopPropigation in this case.

@umassthrower 2012-04-07 23:44:57

Err, actually I went with Art's solution because I didn't want to stop propagation when someone clicks a second menu while the first was still open.

@Andre 2012-05-08 12:32:44

I am also surprised that this solution got so many votes. This will fail for any element outside that has stopPropagation jsfiddle.net/Flandre/vaNFw/3

@Owen 2012-10-16 17:45:10

stackoverflow.com/a/12920446/470159 I've answered a similar one with what i feel is a nice solution

@Martin 2013-01-17 22:13:36

and how to show it from a link in the html?

@Diogo Kollross 2013-01-18 23:49:59

If you show the menu from a click event (eg: a button or link), then the "open menu" click event handler should also call event.stopPropagation().

@Anders 2013-06-18 13:35:46

Nice solution, small and light. But... Does not take overlays like datepickers, popups etc into account. Elements likes these should not trigger hide in my opinion. I added a answer to this question that solves this.

@Stephen Corwin 2013-10-27 02:09:19

Doesn't work if you have more than one menu on the page using this technique. Clicking on any one menu will stop all the other menus from closing.

@Andre Figueiredo 2013-11-29 13:13:06

I cannot say I am surprised this answer got so many upvotes, it works in many cases. But this is not the best solution for this problem! Personally, I like to hand things inside a function in the function scope: stackoverflow.com/questions/152975/… stackoverflow.com/a/7385673/986862

@Adrien Be 2014-04-16 09:32:45

stackoverflow.com/questions/1403615/… complete this answer as pointed by @AndréFigueiredo:

@Tom 2014-05-20 10:52:54

Philip Walton explains very well why this answer isn't the best solution: css-tricks.com/dangers-stopping-event-propagation

@Andy Mercer 2014-05-23 19:07:21

I'm downvoting this because it's not really a solution we should be using. It's dangerous because it has far reaching consequences. As Tom pointed out in a comment above, there is a very in depth article on css-tricks.org about why this answer good.

@Ian S 2014-07-11 19:54:36

This solution breaks other sections of my code. Sorry but i'll have to downvote this. I'm also surprised this is so popular.

@AlexG 2015-02-25 12:09:38

That solution is generally terrible and a maintenance hazard. Basically just a hack that sometimes happen to work.

@Christian Rolle 2015-04-21 14:13:59

This answer is breaking a lot standard behaviour. It should downrated!

@Belal mazlom 2015-08-10 09:25:40

I think this dangers on page performance, details inthis article: css-tricks.com/dangers-stopping-event-propagation

@codeepic 2016-07-25 09:01:14

Here is actually a good explanation why not to use event.stopPropagation() css-tricks.com/dangers-stopping-event-propagation

@Dan Philip 2017-04-14 11:20:24

@Martin James 2018-07-04 15:54:29

I regretfully used a modal plugin that was shockingly using this method to allow clicking outside of the modal to close it, and it took forever to find out why I couldn't delegate events to anything inside of the modal!! I changed the plugin's code to use this instead: $(document).on('click', function(e) { if (!$(e.target).closest('.modal').length && !$(e.target).is('.modal')) modal.close(); }); which is a better solution.

@grant sun 2018-11-20 17:46:17

I would say,:don't use click event, instead, use mouseup event which is less used by other logic

@Sharpey 2018-12-12 00:24:16

Only this solution worked for me. None of those "better" below did. Thank you a lot

@Chu Yeow 2010-12-02 09:53:12

I've had success with something like this:

var $menuscontainer = ...;

$('#trigger').click(function() {
  $menuscontainer.show();

  $('body').click(function(event) {
    var $target = $(event.target);

    if ($target.parents('#menuscontainer').length == 0) {
      $menuscontainer.hide();
    }
  });
});

The logic is: when #menuscontainer is shown, bind a click handler to the body that hides #menuscontainer only if the target (of the click) isn't a child of it.

@DaniG2k 2018-03-07 08:49:30

I just want to make @Pistos answer more apparent since it's hidden in the comments.

This solution worked perfectly for me. Plain JS:

var elementToToggle = $('.some-element');
$(document).click( function(event) {
  if( $(event.target).closest(elementToToggle).length === 0 ) {
    elementToToggle.hide();
  }
});

in CoffeeScript:

elementToToggle = $('.some-element')
$(document).click (event) ->
  if $(event.target).closest(elementToToggle).length == 0
    elementToToggle.hide()

@Jovanni G 2018-02-12 10:39:21

I am surprised nobody actually acknowledged focusout event:

var button = document.getElementById('button');
button.addEventListener('click', function(e){
  e.target.style.backgroundColor = 'green';
});
button.addEventListener('focusout', function(e){
  e.target.style.backgroundColor = '';
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <button id="button">Click</button>
</body>
</html>

@Muhammet Can TONBUL 2019-06-14 13:35:48

You missing my answer i think. stackoverflow.com/a/47755925/6478359

@Rinto George 2018-01-14 08:29:37

I have used below script and done with jQuery.

jQuery(document).click(function(e) {
    var target = e.target; //target div recorded
    if (!jQuery(target).is('#tobehide') ) {
        jQuery(this).fadeOut(); //if the click element is not the above id will hide
    }
})

Below find the HTML code

<div class="main-container">
<div> Hello I am the title</div>
<div class="tobehide">I will hide when you click outside of me</div>
</div>

You can read the tutorial here

@chea sotheara 2018-01-09 03:42:47

$('#propertyType').on("click",function(e){
          self.propertyTypeDialog = !self.propertyTypeDialog;
          b = true;
          e.stopPropagation();
          console.log("input clicked");
      });

      $(document).on('click','body:not(#propertyType)',function (e) {
          e.stopPropagation();
          if(b == true)  {
              if ($(e.target).closest("#configuration").length == 0) {
                  b = false;
                  self.propertyTypeDialog = false;
                  console.log("outside clicked");
              }
          }
        // console.log($(e.target).closest("#configuration").length);
      });

@Muhammet Can TONBUL 2017-12-11 15:15:33

If you are using tools like "Pop-up", you can use the "onFocusOut" event.

window.onload=function(){
document.getElementById("inside-div").focus();
}
function loseFocus(){
alert("Clicked outside");
}
#container{
background-color:lightblue;
width:200px;
height:200px;
}

#inside-div{
background-color:lightgray;
width:100px;
height:100px;

}
<div id="container">
<input type="text" id="inside-div" onfocusout="loseFocus()">
</div>

@Aominé 2017-12-09 13:42:54

if you just want to display a window when you click on a button and undisp this window when you click outside.( or on the button again ) this bellow work good

document.body.onclick = function() { undisp_menu(); };
var menu_on = 0;

function menu_trigger(event){

    if (menu_on == 0)
    {
        // otherwise u will call the undisp on body when 
        // click on the button
        event.stopPropagation(); 

        disp_menu();
    }

    else{
        undisp_menu();
    }

}


function disp_menu(){

    menu_on = 1;
    var e = document.getElementsByClassName("menu")[0];
    e.className = "menu on";

}

function undisp_menu(){

    menu_on = 0;
    var e = document.getElementsByClassName("menu")[0];
    e.className = "menu";

}

don't forget this for the button

<div class="button" onclick="menu_trigger(event)">

<div class="menu">

and the css:

.menu{
    display: none;
}

.on {
    display: inline-block;
}

@Duannx 2017-11-03 07:50:37

Here is a simple solution by pure javascript. It is up-to-date with ES6:

var isMenuClick = false;
var menu = document.getElementById('menuscontainer');
document.addEventListener('click',()=>{
    if(!isMenuClick){
       //Hide the menu here
    }
    //Reset isMenuClick 
    isMenuClick = false;
})
menu.addEventListener('click',()=>{
    isMenuClick = true;
})

@MortenMoulder 2017-11-17 12:41:40

"Up-to-date with ES6" is a pretty bold claim, when the only thing up-to-date with ES6 is doing () => {} instead of function() {}. What you have there is classified as plain JavaScript with a twist of ES6.

@Duannx 2017-11-18 02:40:01

@MortenMoulder: Ya. It's just for attention even though it is actually ES6. But just look at the solution. I think it is good.

@hienbt88 2017-09-13 02:11:50

This works for me

$("body").mouseup(function(e) {
    var subject = $(".main-menu");
    if(e.target.id != subject.attr('id') && !subject.has(e.target).length) {
        $('.sub-menu').hide();
    }
});

@Fabian 2017-07-27 14:00:08

Here is what I do to solve to problem.

$(window).click(function (event) {
    //To improve performance add a checklike 
    //if(myElement.isClosed) return;
    var isClickedElementChildOfMyBox = isChildOfElement(event,'#id-of-my-element');

    if (isClickedElementChildOfMyBox)
        return;

    //your code to hide the element 
});

var isChildOfElement = function (event, selector) {
    if (event.originalEvent.path) {
        return event.originalEvent.path[0].closest(selector) !== null;
    }

    return event.originalEvent.originalTarget.closest(selector) !== null;
}

@Walt 2017-07-18 00:43:37

If someone curious here is javascript solution(es6):

window.addEventListener('mouseup', e => {
        if (e.target != yourDiv && e.target.parentNode != yourDiv) {
            yourDiv.classList.remove('show-menu');
            //or yourDiv.style.display = 'none';
        }
    })

and es5, just in case:

window.addEventListener('mouseup', function (e) {
if (e.target != yourDiv && e.target.parentNode != yourDiv) {
    yourDiv.classList.remove('show-menu'); 
    //or yourDiv.style.display = 'none';
}

});

@Jitendra Damor 2015-12-15 03:50:58

A simple solution for the situation is:

$(document).mouseup(function (e)
{
    var container = $("YOUR SELECTOR"); // Give you class or ID

    if (!container.is(e.target) &&            // If the target of the click is not the desired div or section
        container.has(e.target).length === 0) // ... nor a descendant-child of the container
    {
        container.hide();
    }
});

The above script will hide the div if outside of the div click event is triggered.

You can see the following blog for more information : http://www.codecanal.com/detect-click-outside-div-using-javascript/

@Dan Philip 2017-04-14 04:27:58

The event has a property called event.path of the element which is a "static ordered list of all its ancestors in tree order". To check if an event originated from a specific DOM element or one of its children, just check the path for that specific DOM element. It can also be used to check multiple elements by logically ORing the element check in the some function.

$("body").click(function() {
  target = document.getElementById("main");
  flag = event.path.some(function(el, i, arr) {
    return (el == target)
  })
  if (flag) {
    console.log("Inside")
  } else {
    console.log("Outside")
  }
});
#main {
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">
  <ul>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
    <li>Test-Main</li>
  </ul>
</div>
<div id="main2">
  Outside Main
</div>

So for your case It should be

$("body").click(function() {
  target = $("#menuscontainer")[0];
  flag = event.path.some(function(el, i, arr) {
    return (el == target)
  });
  if (!flag) {
    // Hide the menus
  }
});

@Wolfram 2010-04-05 10:07:36

Now there is a plugin for that: outside events (blog post)

The following happens when a clickoutside handler (WLOG) is bound to an element:

  • the element is added to an array which holds all elements with clickoutside handlers
  • a (namespaced) click handler is bound to the document (if not already there)
  • on any click in the document, the clickoutside event is triggered for those elements in that array that are not equal to or a parent of the click-events target
  • additionally, the event.target for the clickoutside event is set to the element the user clicked on (so you even know what the user clicked, not just that he clicked outside)

So no events are stopped from propagation and additional click handlers may be used "above" the element with the outside-handler.

@TechNyquist 2017-04-11 06:44:32

Nice plugin. Link on "outside events" is dead, while blog post link is alive instead and provides a very useful plugin for "clickoutside" kind events. It's also MIT licensed.

@Gavin 2018-03-21 13:48:35

Great plugin. Worked perfectly. Usage is like so: $( '#element' ).on( 'clickoutside', function( e ) { .. } );

@karthikeyan ganesan 2017-02-24 21:32:00

$(document).on("click",function (event)   
 {   
     console.log(event);
   if ($(event.target).closest('.element').length == 0)
     {
    //your code here
      if ($(".element").hasClass("active"))
      {
        $(".element").removeClass("active");
      }
     }
 });

Try this coding for getting the solution.

@webenformasyon 2011-01-09 23:47:54

Use:

var go = false;
$(document).click(function(){
    if(go){
        $('#divID').hide();
        go = false;
    }
})

$("#divID").mouseover(function(){
    go = false;
});

$("#divID").mouseout(function (){
    go = true;
});

$("btnID").click( function(){
    if($("#divID:visible").length==1)
        $("#divID").hide(); // Toggle
    $("#divID").show();
});

@Lucas 2017-02-09 00:43:51

I know there are a million answers to this question, but I've always been a fan of using HTML and CSS to do most of the work. In this case, z-index and positioning. The simplest way that I have found to do this is as follows:

$("#show-trigger").click(function(){
  $("#element").animate({width: 'toggle'});
  $("#outside-element").show();
});
$("#outside-element").click(function(){
  $("#element").hide();
  $("#outside-element").hide();
});
#outside-element {
  position:fixed;
  width:100%;
  height:100%;
  z-index:1;
  display:none;
}
#element {
  display:none;
  padding:20px;
  background-color:#ccc;
  width:300px;
  z-index:2;
  position:relative;
}
#show-trigger {
  padding:20px;
  background-color:#ccc;
  margin:20px auto;
  z-index:2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="outside-element"></div>
<div id="element">
  <div class="menu-item"><a href="#1">Menu Item 1</a></div>
  <div class="menu-item"><a href="#2">Menu Item 1</a></div>
  <div class="menu-item"><a href="#3">Menu Item 1</a></div>
  <div class="menu-item"><a href="#4">Menu Item 1</a></div>
</div>
<div id="show-trigger">Show Menu</div>

This creates a safe environment, since nothing is going to get triggered unless the menu is actually open and the z-index protects any of the content within the element from creating any misfires upon being clicked.

Additionally, you're not requiring jQuery to cover all of your bases with propagation calls and having to purge all of the inner elements from misfires.

@Waheed 2016-11-01 09:55:50

This might be a better fix for some people.

$(".menu_link").click(function(){
    // show menu code
});

$(".menu_link").mouseleave(function(){
    //hide menu code, you may add a timer for 3 seconds before code to be run
});

I know mouseleave does not only mean a click outside, it also means leaving that element's area.

Once the menu itself is inside the menu_link element then the menu itself should not be a problem to click on or move on.

@Puerto AGP 2017-11-30 23:40:55

mouseleave and some sort of hack might solve it for some people, here's a test jsfiddle.net/1r73jm8m

@Waltur Buerk 2016-11-12 13:57:44

I believe the best way of doing it is something like this.

$(document).on("click", function(event) {
  clickedtarget = $(event.target).closest('#menuscontainer');
  $("#menuscontainer").not(clickedtarget).hide();
});

This type of solution could easily be made to work for multiple menus and also menus that are dynamically added through javascript. Basically it just allows you to click anywhere in your document, and checks which element you clicked in, and selects it's closest "#menuscontainer". Then it hides all menuscontainers but excludes the one you clicked in.

Not sure about exactly how your menus are built, but feel free to copy my code in the JSFiddle. It's a very simple but thoroughly functional menu/modal system. All you need to do is build the html-menus and the code will do the work for you.

https://jsfiddle.net/zs6anrn7/

@Rameez Rami 2015-11-02 08:33:34

After research I have found three working solutions (I forgot the page links for reference)

First solution

<script>
    //The good thing about this solution is it doesn't stop event propagation.

    var clickFlag = 0;
    $('body').on('click', function () {
        if(clickFlag == 0) {
            console.log('hide element here');
            /* Hide element here */
        }
        else {
            clickFlag=0;
        }
    });
    $('body').on('click','#testDiv', function (event) {
        clickFlag = 1;
        console.log('showed the element');
        /* Show the element */
    });
</script>

Second solution

<script>
    $('body').on('click', function(e) {
        if($(e.target).closest('#testDiv').length == 0) {
           /* Hide dropdown here */
        }
    });
</script>

Third solution

<script>
    var specifiedElement = document.getElementById('testDiv');
    document.addEventListener('click', function(event) {
        var isClickInside = specifiedElement.contains(event.target);
        if (isClickInside) {
          console.log('You clicked inside')
        }
        else {
          console.log('You clicked outside')
        }
    });
</script>

@dbarth 2016-07-27 14:49:28

The third solution is by far the most elegant way of checking. It also doesn't involve any overhead of jQuery. Very nice. It helped a lot. Thanks.

@lowtechsun 2017-01-16 08:42:00

I am trying to get the third solution going with multiple elements document.getElementsByClassName, if someone has a clue please share.

@Donnie D'Amato 2017-02-13 17:28:10

@lowtechsun You'd have to loop through to check each.

@indiehjaerta 2018-04-14 00:49:39

Really liked the third solution, however the click triggers before my div has begun to show which hides it again, any idea why?

@RolandiXor 2018-10-09 11:32:44

The third one allows for console.log, sure, but it doesn't let you actually close by setting display to none - because it will do this before the menu is shown. Do you have a solution for this?

@Tiny Giant 2015-05-19 22:52:49

Here is the vanilla JavaScript solution for future viewers.

Upon clicking any element within the document, if the clicked element's id is toggled, or the hidden element is not hidden and the hidden element does not contain the clicked element, toggle the element.

(function () {
    "use strict";
    var hidden = document.getElementById('hidden');
    document.addEventListener('click', function (e) {
        if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none';
    }, false);
})();

(function () {
    "use strict";
    var hidden = document.getElementById('hidden');
    document.addEventListener('click', function (e) {
        if (e.target.id == 'toggle' || (hidden.style.display != 'none' && !hidden.contains(e.target))) hidden.style.display = hidden.style.display == 'none' ? 'block' : 'none';
    }, false);
})();
<a href="javascript:void(0)" id="toggle">Toggle Hidden Div</a>
<div id="hidden" style="display: none;">This content is normally hidden. click anywhere other than this content to make me disappear</div>

If you are going to have multiple toggles on the same page you can use something like this:

  1. Add the class name hidden to the collapsible item.
  2. Upon document click, close all hidden elements which do not contain the clicked element and are not hidden
  3. If the clicked element is a toggle, toggle the specified element.

(function () {
    "use strict";
    var hiddenItems = document.getElementsByClassName('hidden'), hidden;
    document.addEventListener('click', function (e) {
        for (var i = 0; hidden = hiddenItems[i]; i++) {
            if (!hidden.contains(e.target) && hidden.style.display != 'none')
                hidden.style.display = 'none';
        }
        if (e.target.getAttribute('data-toggle')) {
            var toggle = document.querySelector(e.target.getAttribute('data-toggle'));
            toggle.style.display = toggle.style.display == 'none' ? 'block' : 'none';
        }
    }, false);
})();
<a href="javascript:void(0)" data-toggle="#hidden1">Toggle Hidden Div</a>
<div class="hidden" id="hidden1" style="display: none;" data-hidden="true">This content is normally hidden</div>
<a href="javascript:void(0)" data-toggle="#hidden2">Toggle Hidden Div</a>
<div class="hidden" id="hidden2" style="display: none;" data-hidden="true">This content is normally hidden</div>
<a href="javascript:void(0)" data-toggle="#hidden3">Toggle Hidden Div</a>
<div class="hidden" id="hidden3" style="display: none;" data-hidden="true">This content is normally hidden</div>

@Iman Sedighi 2015-01-28 17:24:20

Solution1

Instead of using event.stopPropagation() which can have some side affects, just define a simple flag variable and add one if condition. I tested this and worked properly without any side affects of stopPropagation:

var flag = "1";
$('#menucontainer').click(function(event){
    flag = "0"; // flag 0 means click happened in the area where we should not do any action
});

$('html').click(function() {
    if(flag != "0"){
        // Hide the menus if visible
    }
    else {
        flag = "1";
    }
});

Solution2

With just a simple if condition:

$(document).on('click', function(event){
    var container = $("#menucontainer");
    if (!container.is(event.target) &&            // If the target of the click isn't the container...
        container.has(event.target).length === 0) // ... nor a descendant of the container
    {
        // Do whatever you want to do when click is outside the element
    }
});

@Migio B 2015-02-28 20:28:06

I used this solution with a boolean flag and it's good also with a articulated DOm and also if inside #menucontainer there are a lot of other elements

@shiv 2014-10-09 10:25:46

Using not():

$("#id").not().click(function() {
    alert('Clicked other that #id');
});

@flu 2014-12-04 18:20:48

This doesn't work. not() removes an element from the list of selected elements (api.jquery.com/not). Without a selector as it's parameter it does nothing, thus returning $('#id') which is exactly the opposite of what we're trying to accomplish.

@Manish Shrivastava 2014-10-08 13:30:06

For touch devices like iPad and iPhone we can use this code:

$(document).on('touchstart', function (event) {
    var container = $("YOUR CONTAINER SELECTOR");

    if (!container.is(e.target) &&            // If the target of the click isn't the container...
        container.has(e.target).length === 0) // ... nor a descendant of the container
    {
        container.hide();
    }
});

@Bohdan Lyzanets 2014-07-24 09:41:53

As a variant:

var $menu = $('#menucontainer');
$(document).on('click', function (e) {

    // If element is opened and click target is outside it, hide it
    if ($menu.is(':visible') && !$menu.is(e.target) && !$menu.has(e.target).length) {
        $menu.hide();
    }
});

It has no problem with stopping event propagation and better supports multiple menus on the same page where clicking on a second menu while a first is open will leave the first open in the stopPropagation solution.

@Peter Rader 2014-06-10 12:56:17

Standard HTML:

Surround the menus by a <label> and fetch focus state changes.

http://jsfiddle.net/bK3gL/

Plus: you can unfold the menu by Tab.

@Peter Rader 2014-06-10 13:21:58

plus: you can unfold the menu by <kbd>tab</kbd>

Related Questions

Sponsored Content

21 Answered Questions

[SOLVED] Where should I put <script> tags in HTML markup?

51 Answered Questions

[SOLVED] What is the best way to detect a mobile device?

3 Answered Questions

58 Answered Questions

[SOLVED] How do I redirect to another webpage?

79 Answered Questions

[SOLVED] How do I remove a particular element from an array in JavaScript?

  • 2011-04-23 22:17:18
  • Walker
  • 5828877 View
  • 7265 Score
  • 79 Answer
  • Tags:   javascript arrays

29 Answered Questions

[SOLVED] jQuery scroll to element

  • 2011-07-13 09:49:44
  • DiegoP.
  • 2255615 View
  • 2116 Score
  • 29 Answer
  • Tags:   javascript jquery

14 Answered Questions

[SOLVED] How can I select an element by name with jQuery?

54 Answered Questions

[SOLVED] How do I check if an element is hidden in jQuery?

86 Answered Questions

[SOLVED] How do JavaScript closures work?

3 Answered Questions

[SOLVED] Detect if an element is visible with jQuery

  • 2012-01-07 23:44:02
  • TheCarver
  • 493658 View
  • 495 Score
  • 3 Answer
  • Tags:   javascript jquery

Sponsored Content