1066

I am using this code:

$('body').click(function() {
   $('.form_wrapper').hide();
});

$('.form_wrapper').click(function(event){
   event.stopPropagation();
});

And this HTML:

<div class="form_wrapper">
   <a class="agree" href="javascript:;">I Agree</a>
   <a class="disagree" href="javascript:;">Disagree</a>
</div>

The problem is that I have links inside the div and when they no longer work when clicked.

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
Scott Yu - builds stuff
  • 11,673
  • 8
  • 42
  • 55

40 Answers40

2681

Had the same problem, came up with this easy solution. It's even working recursive:

$(document).mouseup(function(e) 
{
    var container = $("YOUR CONTAINER SELECTOR");

    // if the target of the click isn't the container nor a descendant of the container
    if (!container.is(e.target) && container.has(e.target).length === 0) 
    {
        container.hide();
    }
});
  • 25
    Just put it in my project, but with a minor adjustment, using an array of elements to loop through them all at once. http://jsfiddle.net/LCB5W/ – Thomas Dec 23 '13 at 21:56
  • 3
    2 questions: 1) does this work with touch devices? and 2) is there any reason to use mouseup vs. click? – mpelzsherman Jan 15 '14 at 23:05
  • 7
    @mpelzsherman Many people commented that the snippet works on touch devices but since the post has been edited these comments have somewhat vanished. TBH I don't know whether I used "mouseup" for a specific reason but if it also works with "click" I see no reason why you shouldn't use "click". –  Jan 16 '14 at 10:03
  • @prc322 - What if in case there are nested elements which are generated dynamically in "container"? I tried your code , but the 2nd check where its checking for descendants "container.has(e.target).length === 0" fails and it returns true, even if its a descendant. – whyAto8 Feb 17 '14 at 07:31
  • @whyAto8: change your event listener... perhaps `$(document).on('click', function(e) { [...] });` – Rob W Feb 26 '14 at 14:49
  • @HalfCrazed - I actually realized later on, what was wrong. I had taken this code "var container = $("YOUR CONTAINER SELECTOR");" outside and used it in kind of global function. Hence, when dynamically building list, the container wasnt realizing if it had descendants. Fixed it by writing it inside as given in code. – whyAto8 Mar 05 '14 at 10:18
  • 4
    This solution does not take into account the event should be thrown only one time. – Loenix Mar 27 '14 at 10:57
  • @Loenix: Can you elaborate? I don't quite get what you mean. –  Mar 27 '14 at 14:42
  • 7
    I needed that the container is hide one time with this event, this callback should be destroyed when used. To do that, i used namespace on click event with bind("click.namespace") and when the event occurred, i call unbind("click.namespace"). And finally, i used $(e.target).closest(".container").length to recognize container ... So, i did not use any trick from this answer :D – Loenix Mar 27 '14 at 15:43
  • @Loenix Ah well yes. It is true that the snippet does not take that into account but that wasn't a requirement from the OP anyways. –  Mar 27 '14 at 17:42
  • @Loenix I was exactly wondering how to destroy only this callback (not all the ones attached to `$(document)`. http://stackoverflow.com/a/3973060/759452 seems to refer to the technic you mention, is this correct? – Adriano Apr 16 '14 at 09:46
  • another live example using this technic http://jsfiddle.net/6fcDJ/ - using `.closest()` as @Loenix mentioned is another solution. – Adriano Jun 30 '14 at 14:51
  • I think jQuery stop propagation is the best solution http://stackoverflow.com/a/23359423/2459296 – MD SHAHIDUL ISLAM Aug 03 '14 at 06:42
  • I found it better to have $(document).click(function (e) instead of $(document).mouseup(function (e) because the first click usually bring the menu up and the next click anywhere will take the menu away. – Venugopal M Aug 08 '14 at 08:51
  • 85
    **Remembering** to use [`$("YOUR CONTAINER SELECTOR").unbind( 'click', clickDocument );`](http://api.jquery.com/unbind/) just beside *`.hide()`*. So `document` don't keep listening for clicks. – brasofilo Oct 12 '14 at 12:21
  • Just want to let others know that this solution still works on jQuery 2.2 Thanks – andrex Feb 03 '15 at 23:34
  • 17
    For best practices I'd wrote `$(document).on("mouseup.hideDocClick", function () { ... });` in the function that opens the container, and `$(document).off('.hideDocClick');` on hide function. Using [namespaces](http://api.jquery.com/on/#event-names) I'm not removing other possible `mouseup` listeners attached to the document. – campsjos Feb 04 '15 at 17:54
  • 1
    This actually didn't work for me. I used: $(document).off('mouseup'); $(document).on('mouseup', function (e) { if( !container.is(e.target) && container.find('#' + e.target.id).length === 0 ) { $(document).off('mouseup'); container.hide(); } }); – Jonathan.Brink Feb 07 '15 at 01:25
  • Excellent! This approach works just the way I wanted it to (I am writing a custom dropdown box, that can contain any widgets, but if the click was outside the dropdown container and its widgets, it was supposed to close - now it can! ) – Igor Mar 09 '15 at 15:56
  • You know one of those situations where you search for a solution, and nothing works. Google after google, then you finally find something perfect after an hour? This is that perfection. Thank you. – batoutofhell Mar 16 '15 at 14:21
  • is there a way to do this in some other elements' focus out event ? – prime Nov 04 '15 at 09:05
  • @brasofilo, could you please explain more – Adib Aroui Dec 14 '15 at 08:36
  • @whitelettersinblankpapers: Just add that line inside the `if() {}`, using the same selector as `var container =` – brasofilo Jan 14 '16 at 03:57
  • 3
    @brasofilo this doesn't work for me. getting ReferenceError: clickDocument is not defined. cause there is no handler. how should the handler look like?! – dstN Jul 15 '16 at 14:09
  • I used similar in my Angular JS 4 application in TypeScript code. – Ziggler May 11 '17 at 18:23
  • Problem if select2 is placed inside clickable element, after clicking on – fsasvari Nov 22 '17 at 11:25
  • Just change the first line to `$(document).on('mousedown keydown', function (e)` And it will work with keyboard also – Anuj Feb 11 '18 at 12:13
  • 2
    I just wanted to add from a previous comment about getting an array and looping through - you can just do: `let container = $(".thing1, .thing2, .thing3, .thing4");` without having to change the rest of the code. – Robert Pounder Feb 20 '18 at 09:48
  • In some cases `mousedown` is a better choice. I used it to hide a suggestion list on Google maps when dragging starts. – Ali Sheikhpour May 08 '19 at 05:06
  • I did this, but because of this the button which i click to open a popup doesnt work anymore, since clicking that button again hides the popup as it's outside the popup. How do I fix this? –  Jan 13 '20 at 07:52
  • @brasofilo; I followed your advise but then the code was not working properly anymore. I am using a link to show the container and after I inserted your code, I always had to click the link twice to open the container. – Black Feb 14 '20 at 13:14
  • 3
    Maybe a small add: `$(document).on('mouseup touchend focusin', function functionName(e) {...});`. Should work for desktop, touch devices, and the `focusin`, if used correctly, should handle keyboard navigation when tabbing out of the div area for accessibility behavior (e.g. close the container on tab-out). And a not so pretty version of the condition might be: `if ($(e.target).parents(".parent-div-class").length === 0)`. Though this answer offers a better check! – Prestosaurus Feb 16 '20 at 19:21
  • I just use this code for my issue that is submenu div not disappearing if I click outside it.. it working fine but submenu should again disappear if i also click on its parent menu. its not working. – Ali Nov 30 '20 at 13:29
  • @Ali use a similar class name for both pop-over and the button to show/hide and assign that class name to container variable. but instead of `container.hide();` use id of pop-over to hide it, otherwise the button will hide – Rafe Jan 13 '21 at 08:16
  • I used this solution, but instead of "container" I wanted to change a boolean class property, hence `container.hide();` was replaced by `this.divDisplayed = false`. I got an error on the "this", it was not recognized correctly, so I switched to the fat arrow syntax - i.e switch from `function(e) {}` to `(e) => {}` (see https://stackoverflow.com/a/57839163/11724795 ). Now it works – ToddEmon Jun 09 '22 at 08:36
  • This is working on all device for me : https://stackoverflow.com/a/74847067/5287215 – Mahmudul Hasan Sohag Dec 19 '22 at 06:50
  • mousedown should be used for yet another reason: when selecting by mouse dragging something inside the container (text, input..) but you release mouse button outside at the end of the select, you don't want it to hide – e-motiv Jun 04 '23 at 14:00
212

You'd better go with something like this:

var mouse_is_inside = false;

$(document).ready(function()
{
    $('.form_content').hover(function(){ 
        mouse_is_inside=true; 
    }, function(){ 
        mouse_is_inside=false; 
    });

    $("body").mouseup(function(){ 
        if(! mouse_is_inside) $('.form_wrapper').hide();
    });
});
Makram Saleh
  • 8,613
  • 4
  • 27
  • 44
  • How clever! Is this technique standard? – advait Nov 05 '10 at 08:42
  • @advait I didn't see it used before. It's all about the `hover` event handler, which opens up many possibilities. – Makram Saleh Nov 05 '10 at 16:21
  • I like David Andres solution more, because it doesn’t add another variable and minimizes program state. – Rafael Bugajewski May 07 '11 at 20:39
  • @Rafael ok, but the user might click on something *inside* the `form_wrapper` which will return a different `e.target`, but still the div should not be hidden. – Makram Saleh May 08 '11 at 10:49
  • 6
    I don't consider this to be a good solution since it lets people think it is okay to populate the window-object (= using global variables). –  Sep 20 '12 at 14:07
  • 2
    Just to add something to what @prc322 said, you can wrap your code with an anonymous function and have it called immediately. `(function() { // ... code })();` I don't remember the name os this pattern, but it's super useful! All your declared variables will reside inside the function and won't pollute the global namespace. – pedromanoel Oct 09 '13 at 19:08
  • 3
    @prc322 If you don't even know how to change a variable's scope, then you're right, this solution is not good for you... and neither is JavaScript. If you're just copying and pasting code from Stack Overflow, you're gonna have a lot more problems than possibly overwriting something in the window object. – Gavin Oct 18 '13 at 04:45
  • This will not work on mobile. There is no hover there so you won't be ablo to do the hiding. – bwitkowicz Jan 02 '15 at 14:45
  • Well before coming to this thread, i tried it and it did not work... coz when there are more elements than just the one you are watching for mouseout event then the same happens. you end up throwing mouseout when still mouse is inside the subjected element. So I realized that the top-answer in this thread is the final. I implemented that and it worked for me. I also added a keyup event to close the div when pressed Esc. Just telling! – KMX Oct 16 '16 at 07:22
108

This code detects any click event on the page and then hides the #CONTAINER element if and only if the element clicked was neither the #CONTAINER element nor one of its descendants.

$(document).on('click', function (e) {
    if ($(e.target).closest("#CONTAINER").length === 0) {
        $("#CONTAINER").hide();
    }
});
Case
  • 4,244
  • 5
  • 35
  • 53
79

You might want to check the target of the click event that fires for the body instead of relying on stopPropagation.

Something like:

$("body").click
(
  function(e)
  {
    if(e.target.className !== "form_wrapper")
    {
      $(".form_wrapper").hide();
    }
  }
);

Also, the body element may not include the entire visual space shown in the browser. If you notice that your clicks are not registering, you may need to add the click handler for the HTML element instead.

David Andres
  • 31,351
  • 7
  • 46
  • 36
  • Yep, now the links work! But for some reason, when I click the link, it fires it twice. – Scott Yu - builds stuff Sep 10 '09 at 06:27
  • I ended up using a variation of this. I first check if the element is visible then if the target.hasClass I hide it. – Hawkee Apr 23 '12 at 20:03
  • and dont forget `e.stopPropagation();` if you have other click listener – Darin Kolev Jun 16 '13 at 13:32
  • 5
    -1. This hides the `form_wrapper` when you click one of its children, which isn't the desired behaviour. Use prc322's answer instead. – Mark Amery Jul 17 '13 at 21:04
  • 1
    @Tallboy, I appreciate your perspective here. I get it, it's better to not waste vertical space, at least when you need to print code. I have heard it said that condensing braces makes code more readable, but I would argue that the code within these methods should already be short enough to fit on a screen regardless of where braces are placed. If not, then there may be bigger issues at hand. Years ago, I found the balanced approach to brace placement more aesthetically pleasing but over time have transitioned to the form you recommend. – David Andres Feb 27 '21 at 00:14
58

Live DEMO

Check click area is not in the targeted element or in it's child

$(document).click(function (e) {
    if ($(e.target).parents(".dropdown").length === 0) {
        $(".dropdown").hide();
    }
});

UPDATE:

jQuery stop propagation is the best solution

Live DEMO

$(".button").click(function(e){
    $(".dropdown").show();
     e.stopPropagation();
});

$(".dropdown").click(function(e){
    e.stopPropagation();
});

$(document).click(function(){
    $(".dropdown").hide();
});
The Codesee
  • 3,714
  • 5
  • 38
  • 78
MD SHAHIDUL ISLAM
  • 14,325
  • 6
  • 82
  • 89
  • Thanks for the update, perfect! Does it work on touch devices? – FFish Apr 08 '16 at 09:45
  • 1
    In the case, you have multiple dropdowns on a page. I think you will need to close all dropdowns before opening the `clicked` one. Otherwise, the `stopPropagation` would make possible that multiple dropdowns are open at the same time. – T04435 May 14 '19 at 02:00
  • Thanks a lot, in my case propagation was the only working solution – Ryan NZ Jul 06 '20 at 08:06
  • `$(".dropdown").click(function(e){ e.stopPropagation(); });` this is working fine for me ... thanks – w.Daya Nov 16 '21 at 07:38
  • I preferred this method, thanks! – cwiggo Jan 19 '22 at 21:31
21
$(document).click(function(event) {
    if ( !$(event.target).hasClass('form_wrapper')) {
         $(".form_wrapper").hide();
    }
});
meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
  • 2
    Hmmm... If I click on something INSIDE the div, the entire div disappears for some reason. – Scott Yu - builds stuff Sep 12 '09 at 19:15
  • 13
    Instead of checking if the target has the class, try: if ( $(event.target).closest('.form_wrapper).get(0) == null ) { $(".form_wrapper").hide(); } This will insure that clicking things inside of the div won't hide the div. – John Haager Apr 21 '10 at 17:49
19

A solution without jQuery for the most popular answer:

document.addEventListener('mouseup', function (e) {
    var container = document.getElementById('your container ID');

    if (!container.contains(e.target)) {
        container.style.display = 'none';
    }
}.bind(this));

MDN: https://developer.mozilla.org/en/docs/Web/API/Node/contains

Community
  • 1
  • 1
MartyIX
  • 27,828
  • 29
  • 136
  • 207
18

Updated the solution to:

  • use mouseenter and mouseleave instead
  • of hover use live event binding

var mouseOverActiveElement = false;

$('.active').live('mouseenter', function(){
    mouseOverActiveElement = true; 
}).live('mouseleave', function(){ 
    mouseOverActiveElement = false; 
});
$("html").click(function(){ 
    if (!mouseOverActiveElement) {
        console.log('clicked outside active element');
    }
});
benvds
  • 3,690
  • 1
  • 17
  • 14
10

Live demo with ESC functionality

Works on both Desktop and Mobile

var notH = 1,
    $pop = $('.form_wrapper').hover(function(){ notH^=1; });

$(document).on('mousedown keydown', function( e ){
  if(notH||e.which==27) $pop.hide();
});

If for some case you need to be sure that your element is really visible when you do clicks on the document: if($pop.is(':visible') && (notH||e.which==27)) $pop.hide();

Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
9

Wouldn't something like this work?

$("body *").not(".form_wrapper").click(function() {

});

or

$("body *:not(.form_wrapper)").click(function() {

});
Nishant
  • 54,584
  • 13
  • 112
  • 127
MRVDOG
  • 1,717
  • 2
  • 13
  • 20
  • 4
    This answer is not correct. Like many answers here, this will hide the `.form_wrapper` when you click its children (among other problems). – Mark Amery Jul 17 '13 at 21:09
8

Instead of listening to every single click on the DOM to hide one specific element, you could set tabindex to the parent <div> and listen to the focusout events.

Setting tabindex will make sure that the blur event is fired on the <div> (normally it wouldn't).

So your HTML would look like:

<div class="form_wrapper" tabindex="0">
    <a class="agree" href="javascript:;">I Agree</a>
    <a class="disagree" href="javascript:;">Disagree</a>
</div>

And your JS:

$('.form_wrapper').on('focusout', function(event){
    $('.form_wrapper').hide();
});
Oscar
  • 915
  • 10
  • 15
8

So many answers, must be a right of passage to have added one... I didn't see a current (jQuery 3.1.1) answers - so:

$(function() {
    $('body').on('mouseup', function() {
        $('#your-selector').hide();
    });
});
zak
  • 776
  • 10
  • 10
7

Even sleaker:

$("html").click(function(){ 
    $(".wrapper:visible").hide();
});
Olivenbaum
  • 87
  • 1
  • 1
  • 4
    This answer is not correct. This will hide the `.wrapper` no matter where you click on the page, which isn't what was asked for. – Mark Amery Jul 17 '13 at 21:10
6

Here's a jsfiddle I found on another thread, works with esc key also: http://jsfiddle.net/S5ftb/404

    var button = $('#open')[0]
    var el     = $('#test')[0]

    $(button).on('click', function(e) {
      $(el).show()
      e.stopPropagation()
    })

    $(document).on('click', function(e) {
      if ($(e.target).closest(el).length === 0) {
        $(el).hide()
      }
    })

    $(document).on('keydown', function(e) {
      if (e.keyCode === 27) {
        $(el).hide()
      }
    })
djv
  • 466
  • 6
  • 15
  • I see it detects whether the 'click' event is within the #test element.. tried tesing links as http://jsfiddle.net/TA96A/ & looks like they might work. – Thomas W Jul 18 '13 at 01:28
  • Yes, it looks like jsfiddle blocks outside links. If you use http:// jsfiddle.net you'll see the result page processes the link :) – djv Jul 19 '13 at 04:51
6

And for Touch devices like IPAD and IPHONE we can use following 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();
    }
});
Code Spy
  • 9,626
  • 4
  • 66
  • 46
6

(Just adding on to prc322's answer.)

In my case I'm using this code to hide a navigation menu that appears when the user clicks an appropriate tab. I found it was useful to add an extra condition, that the target of the click outside the container is not a link.

$(document).mouseup(function (e)
{
    var container = $("YOUR CONTAINER SELECTOR");

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

This is because some of the links on my site add new content to the page. If this new content is added at the same time that the navigation menu disappears it might be disorientating for the user.

shngrdnr
  • 109
  • 2
  • 10
6

Built off of prc322's awesome answer.

function hideContainerOnMouseClickOut(selector, callback) {
  var args = Array.prototype.slice.call(arguments); // Save/convert arguments to array since we won't be able to access these within .on()
  $(document).on("mouseup.clickOFF touchend.clickOFF", function (e) {
    var 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();
      $(document).off("mouseup.clickOFF touchend.clickOFF");
      if (callback) callback.apply(this, args);
    }
  });
}

This adds a couple things...

  1. Placed within a function with a callback with "unlimited" args
  2. Added a call to jquery's .off() paired with a event namespace to unbind the event from the document once it's been run.
  3. Included touchend for mobile functionality

I hope this helps someone!

WiseOlMan
  • 926
  • 2
  • 11
  • 26
5

if you have trouble with ios, mouseup is not working on apple device.

does mousedown /mouseup in jquery work for the ipad?

i use this:

$(document).bind('touchend', function(e) {
        var container = $("YOURCONTAINER");

          if (container.has(e.target).length === 0)
          {
              container.hide();
          }
      });
Community
  • 1
  • 1
user2271066
  • 61
  • 1
  • 2
4
 $('body').click(function(event) {
    if (!$(event.target).is('p'))
    {
        $("#e2ma-menu").hide();
    }
});

p is the element name. Where one can pass the id or class or element name also.

AlexVogel
  • 10,601
  • 10
  • 61
  • 71
Abhishek
  • 401
  • 4
  • 4
4

Copied from https://sdtuts.com/click-on-not-specified-element/

Live demo http://demos.sdtuts.com/click-on-specified-element

$(document).ready(function () {
    var is_specified_clicked;
    $(".specified_element").click(function () {
        is_specified_clicked = true;
        setTimeout(function () {
            is_specified_clicked = false;
        }, 200);
    })
    $("*").click(function () {
        if (is_specified_clicked == true) {
//WRITE CODE HERE FOR CLICKED ON OTHER ELEMENTS
            $(".event_result").text("you were clicked on specified element");
        } else {
//WRITE CODE HERE FOR SPECIFIED ELEMENT CLICKED
            $(".event_result").text("you were clicked not on specified element");
        }
    })
})
user3151197
  • 347
  • 1
  • 3
  • 14
4
var n = 0;
$("#container").mouseenter(function() {
n = 0;

}).mouseleave(function() {
n = 1;
});

$("html").click(function(){ 
if (n == 1) {
alert("clickoutside");
}
});
Gary
  • 49
  • 1
3

Return false if you click on .form_wrapper:

$('body').click(function() {
  $('.form_wrapper').click(function(){
  return false
});
   $('.form_wrapper').hide();
});

//$('.form_wrapper').click(function(event){
//   event.stopPropagation();
//});
bogo
  • 31
  • 1
3

Attach a click event to top level elements outside the form wrapper, for example:

$('#header, #content, #footer').click(function(){
    $('.form_wrapper').hide();
});

This will also work on touch devices, just make sure you don't include a parent of .form_wrapper in your list of selectors.

Pumba
  • 39
  • 3
3

var exclude_div = $("#ExcludedDiv");;  
$(document).click(function(e){
   if( !exclude_div.is( e.target ) )  // if target div is not the one you want to exclude then add the class hidden
        $(".myDiv1").addClass("hidden");  

}); 

FIDDLE

SharmaPattar
  • 2,472
  • 3
  • 21
  • 23
3

$(document).ready(function() {
 $('.modal-container').on('click', function(e) {
   if(e.target == $(this)[0]) {
  $(this).removeClass('active'); // or hide()
   }
 });
});
.modal-container {
 display: none;
 justify-content: center;
 align-items: center;
 position: absolute;
 top: 0;
 left: 0;
 right: 0;
 bottom: 0;
 background-color: rgba(0,0,0,0.5);
 z-index: 999;
}

.modal-container.active {
    display: flex;  
}

.modal {
 width: 50%;
 height: auto;
 margin: 20px;
 padding: 20px;
 background-color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="modal-container active">
 <div class="modal">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean ac varius purus. Ut consectetur viverra nibh nec maximus. Nam luctus ligula quis arcu accumsan euismod. Pellentesque imperdiet volutpat mi et cursus. Sed consectetur sed tellus ut finibus. Suspendisse porttitor laoreet lobortis. Nam ut blandit metus, ut interdum purus.</p>
 </div>
</div>
RustBeard
  • 81
  • 10
2

i did it like this:

var close = true;

$(function () {

    $('body').click (function(){

        if(close){
            div.hide();
        }
        close = true;
    })


alleswasdenlayeronclicknichtschliessensoll.click( function () {   
        close = false;
    });

});
2
dojo.query(document.body).connect('mouseup',function (e)
{
    var obj = dojo.position(dojo.query('div#divselector')[0]);
    if (!((e.clientX > obj.x && e.clientX <(obj.x+obj.w)) && (e.clientY > obj.y && e.clientY <(obj.y+obj.h))) ){
        MyDive.Hide(id);
    }
});
Abed Yaseen
  • 522
  • 4
  • 12
2

By using this code you can hide as many items as you want

var boxArray = ["first element's id","second element's id","nth element's id"];
   window.addEventListener('mouseup', function(event){
   for(var i=0; i < boxArray.length; i++){
    var box = document.getElementById(boxArray[i]);
    if(event.target != box && event.target.parentNode != box){
        box.style.display = 'none';
    }
   }
})
Steve Zelaznik
  • 616
  • 7
  • 16
Mahdi Younesi
  • 6,889
  • 2
  • 20
  • 51
2

What you can do is bind a click event to the document that will hide the dropdown if something outside the dropdown is clicked, but won't hide it if something inside the dropdown is clicked, so your "show" event (or slidedown or whatever shows the dropdown)

    $('.form_wrapper').show(function(){

        $(document).bind('click', function (e) {
            var clicked = $(e.target);
            if (!clicked.parents().hasClass("class-of-dropdown-container")) {
                 $('.form_wrapper').hide();
            }
        });

    });

Then when hiding it, unbind the click event

$(document).unbind('click');
jeffsaracco
  • 1,259
  • 12
  • 21
2

Working on all device for me ( 2023 ) ;)

<section class="form-wrapper">
 <div class="popup-container">
  Popup Me
 </div>
</section>



$('.form-wrapper').on('click', function(e) {
  var pop_container = $(".popup-container");

  // if the target of the click isn't the pop_container nor a descendant of the pop_container
  if (!pop_container.is(e.target) && pop_container.has(e.target).length === 0) {
      //you action here 
      pop_container.hide();
  }
});
1

You might encounter some issues when using the accepted answer with pop-up windows. There might be a case where clicking on a random place might result in unwanted actions, i.e. clicking on a button by mistake might take you to a new page.

I am not sure if this is the most efficient solution but to prevent this I would suggest using a screenmask. Make sure the screenmask is right below the <body> tag so that it can cover all the screen by width:100%; height: 100%. Also note that it is above all elements by z-index: 99. If you want another item or div to be clickable when the screenmask is active, just assign a higher z-index to that item or div.

The screenmask is initially not-displayed (displayed:none) and it calls a hide function when clicked (onclick="hidemenu()").

<body>
<div class="screenmask" onclick="hidemenu()" style="position:fixed; width: 100%; height: 100%; top: 0px; right: 0px; display: none; z-index: 99;"></div>

The javascript functions to deal with "multiple distinct pop-up menus on the same page" might be like the ones below:

<script>
// an element with onclick="showmenu('id_here')" pops a menu in the screen
function showmenu(id) {  
  var popmenu = document.getElementById(id); // assume popmenu is of class .cardmenu
  $('.cardmenu').hide();   // clear the screen from other popmenus first
  $(popmenu).show();          // pop the desired specific menu
  $('.screenmask').show(); // activate screenmask
}
    
function hidemenu() {      // called when clicked on the screenmask
  $('.cardmenu').hide();   // clear the screen from all the popmenus
  $('.screenmask').hide(); // deactivate screenmask
}
</script>
Xfce4
  • 557
  • 5
  • 28
1

According to the docs, .blur() works for more than the <input> tag. For example:

$('.form_wrapper').blur(function(){
   $(this).hide();
});
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Bizley
  • 43
  • 1
  • -1, doesn't work. Very interesting idea, but the jQuery docs are wrong. See https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.onblur, for instance: "In contrast to MSIE--in which almost all kinds of elements receive the blur event--almost all kinds of elements on Gecko browsers do NOT work with this event." Also, tested in Chrome, and `div`s never blur - blur events can't even bubble to them from their children. Finally, even if the above weren't true, this would only work if you made sure that the `.form_wrapper` was in focus before the user clicked off it. – Mark Amery Jul 17 '13 at 21:18
1

So many answers I could not use. Instead I took the accepted answer (which works well) and shortened to this (using a descendant selector):

$(document).mouseup(function(e) 
{
    if (!$(e.target).is("#targetSelector,#targetSelector *")) {
        $('#targetSelector').hide();
    }
});

As it only operates at user-interaction speed, no point assigning to a variable

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
0
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js">
</script>
<script>
$(document).ready(function(){
  $("#hide").click(function(){
    $("p").hide();
  });
  $("#show").click(function(){
    $("p").show();
  });
});
</script>
</head>
<body>
<p>If you click on the "Hide" button, I will disappear.</p>
<button id="hide">Hide</button>
<button id="show">Show</button>
</body>
</html>
Bhushan wagh
  • 187
  • 1
  • 14
0

Toggle for regular and touch devices

I read some answers here a while back and created some code I use for div's that function as popup bubbles.

$('#openPopupBubble').click(function(){
    $('#popupBubble').toggle();

    if($('#popupBubble').css('display') === 'block'){
        $(document).bind('mousedown touchstart', function(e){
            if($('#openPopupBubble').is(e.target) || $('#openPopupBubble').find('*').is(e.target)){
                $(this).unbind(e);
            } 
            else if(!$('#popupBubble').find('*').is(e.target)){
                $('#popupBubble').hide();
                $(this).unbind(e);
            }
        });
    }
});

You can also make this more abstract using classes and select the correct popup bubble based on the button that triggered the click event.

$('body').on('click', '.openPopupBubble', function(){
    $(this).next('.popupBubble').toggle();

    if($(this).next('.popupBubble').css('display') === 'block'){
        $(document).bind('mousedown touchstart', function(e){
            if($(this).is(e.target) || $(this).find('*').is(e.target)){
                $(this).unbind(e);
            } 
            else if(!$(this).next('.popupBubble').find('*').is(e.target)){
                $(this).next('.popupBubble').hide();
                $(this).unbind(e);
            }
        });
    }
});
Sceptic
  • 1,659
  • 2
  • 15
  • 25
0

This solution should work fine, it's easy :

jQuery(document).ready(function($) {
    jQuery(document).click(function(event) {
        if(typeof  jQuery(event.target).attr("class") != "undefined") {
            var classnottobeclickforclose = ['donotcountmeforclickclass1', 'donotcountmeforclickclass2','donotcountmeforclickclass3'];
            var arresult = jQuery.inArray(jQuery(event.target).attr("class"), classnottobeclickforclose);
            if (arresult < 0) {
                jQuery(".popup").hide();
            }
        }
    });
});

In Above code change donotcountmeforclickclass1 , donotcountmeforclickclass2 etc with classes which you have used to show popup or on it's click popup should not effect so you have to definitely add class which you are using to open popup.

Change .popup class with popup class.

Den Pat
  • 1,118
  • 10
  • 17
0

I was working over a search box which shows the autocomplete according to the processed keywords. When i dont want to click over any option then i will use the below code to hide the processed list and it works.

$(document).click(function() {
 $('#suggestion-box').html("");
});

Suggestion-box is my autocomplete container where i am showing the values.

Vivek
  • 1,446
  • 18
  • 27
0

var $container = $("#popup_container");

$container.click(function(e) {
    if (e.target.id == $container.attr("id")) {
      $(this).hide();
  }
});
#popup_container {
  background: rgba(200,200,200,0.6);
  width: 100vh;
  height: 100vh;
  position: fixed;
  display: flex;
  justify-content: center;
  align-items: center;
}

#popup {
  background: yellow;
  border: 1px solid black;
  position: absolute;
  width: 50%;
  height: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="popup_container">
  <div id="popup">
    Popup
  </div>
</div>

https://jsfiddle.net/041pj7re/

Black
  • 18,150
  • 39
  • 158
  • 271
-2
$(document).ready(function() {

$('.headings').click(function () {$('#sub1').css("display",""); });
$('.headings').click(function () {return false;});
$('#sub1').click(function () {return false;});
$('body').click(function () {$('#sub1').css("display","none");

})});
Verbeia
  • 4,400
  • 2
  • 23
  • 44
Peter
  • 1
-4

I think it can be a lot easier. I did it like this:

$(':not(.form_wrapper)').click(function() {
    $('.form_wrapper').hide();
});
SPRBRN
  • 2,406
  • 4
  • 35
  • 48
  • 1
    I would avoid this, you're going to add click event handlers to every element in your document besides the .form_wrapper. – JayD3e Feb 26 '13 at 21:48
  • @JayD3e Plus this will hide the `.form_wrapper` when you click an element within it. – Mark Amery Jul 17 '13 at 21:36