25

I want to hide a div by clicking on the close link in it, or by clicking anywhere outside that div.

I am trying following code, it opens and close the div by clicking close link properly, but if I have problem to close it by clicking anywhere outside the div.

$(".link").click(function() {
  $(".popup").fadeIn(300);
}

);
$('.close').click(function() {
  $(".popup").fadeOut(300);
}

);
$('body').click(function() {
  if (!$(this.target).is('.popup')) {
    $(".popup").hide();
  }
}

);
<div class="box">
  <a href="#" class="link">Open</a>
  <div class="popup">
    Hello world
    <a class="close" href="#">Close</a>
  </div>
</div>

Demo: http://jsfiddle.net/LxauG/

athi
  • 1,683
  • 15
  • 26
user1355300
  • 4,867
  • 18
  • 47
  • 71
  • 3
    Possible dublicate: http://stackoverflow.com/questions/1403615/use-jquery-to-hide-a-div-when-the-user-clicks-outside-of-it – Lost_In_Library Jul 31 '13 at 08:59
  • event.target not this.target. Or if you don't want to use delegated event you could use the focus event of div – A. Wolff Jul 31 '13 at 08:59
  • If you are using jQuery UI or bootstrap, I suggest you to look at the `.Modal()` component which is a charm to use and implements the behaviour you want. – Daniel W. Jul 31 '13 at 09:00
  • 1
    @TusharGupta you already posted that in your answer. your fiddle doesn't even work for me – Daniel W. Jul 31 '13 at 09:04
  • 1
    You shouldn't be using JQuery 2.x. The best stable version of JQuery is 1.9.1 as the developers themselves admitted. Stick to 1.9.1 to be sure that it's not some JQuery function failing. – Parrotmaster Jul 31 '13 at 09:05
  • Possible duplicate of [How do I prevent a parent's onclick event from firing when a child anchor is clicked?](https://stackoverflow.com/questions/1369035/how-do-i-prevent-a-parents-onclick-event-from-firing-when-a-child-anchor-is-cli) – Liam Oct 08 '18 at 14:41

8 Answers8

36

An other way which makes then your jsfiddle less buggy (needed double click on open).

This doesn't use any delegated event to body level

Set tabindex="-1" to DIV .popup ( and for style CSS outline:0 )

DEMO

$(".link").click(function(e){
    e.preventDefault();
    $(".popup").fadeIn(300,function(){$(this).focus();});
});

$('.close').click(function() {
   $(".popup").fadeOut(300);
});
$(".popup").on('blur',function(){
    $(this).fadeOut(300);
});
A. Wolff
  • 74,033
  • 9
  • 94
  • 155
  • 3
    This is the best answer. Fixed both the buggy clicking and the body click. I don't understand why it was so buggy tho. I fixed the code by using the most stable JQuery version 1.9.1 and putting the JQuery code in a document.ready, ensuring nothing happens before the DOM is ready. http://jsfiddle.net/LxauG/14/ – Parrotmaster Jul 31 '13 at 09:09
  • @Parrotmaster because the delegated event was fired on open click, a stopPropagation should be used too with OP's original code – A. Wolff Jul 31 '13 at 09:10
  • 1
    For future reference, take note that the `fadeOut` is key here for it to work correctly. Without the delayed fade, the blur event triggers before any event from element inside the popup div. – Emile Bergeron Mar 16 '16 at 01:42
  • it's good solution if your popup contains static content which I mean to say if your popup contains form inputs or anything which can have focus property then div focus will be blurred and your button or input will get the focus which causes to hide the popup. – siddhesh Nov 13 '17 at 14:46
28

You need

$('body').click(function(e) {
    if (!$(e.target).closest('.popup').length){
        $(".popup").hide();
    }
});
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
8

I'd suggest using the stopPropagation() method as shown in the modified fiddle:

Fiddle

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

$('.popup').click(function(e) {
    e.stopPropagation();
});

That way you can hide the popup when you click on the body, without having to add an extra if, and when you click on the popup, the event doesn't bubble up to the body by going through the popup.

Jonas Grumann
  • 10,438
  • 2
  • 22
  • 40
  • Your fiddle seems pretty buggy. I had to spam click the Open link a few times before the green block appeared, and even then I had difficulty closing it. – Parrotmaster Jul 31 '13 at 09:01
  • 1
    Yes, but so does the original fiddle, I just worried about the event propagating thing – Jonas Grumann Jul 31 '13 at 09:01
  • @JonasGrumann Thanks, yes, the original has that problem if i add the last function. Thats why I posted the question cos I'm having trouble to close the .popup after clicking anywhere outside it. – user1355300 Jul 31 '13 at 09:10
  • This works fine, but what if i have multiple popups and i hide them in on click for body, they all will be stop and i need to hide the remaining popups after e.stopPropagation(). Is there any better solution. – Santosh Jul 11 '14 at 07:15
  • @helpme I don't understand what you're saying, could you explain it a little better so I can help you? – Jonas Grumann Jul 11 '14 at 07:44
  • let me explain with an example. assume that there are two buttons A and B which opens two different popups say popupA and popupB now when i click on out side i want to close those popups so i write popupA.hide() and popupB.hide() inside $('body').click function. now to make buttons works i add e.stopPropagation() inside button click function Incase i open popupA and without clicking outside the popupA i click on button B which opens popupB without closing popupA. so i need to write code to hide popupA inside button A click function similarly for button A. do you see the problem.?Thanks – Santosh Jul 11 '14 at 10:51
  • I see. I think we're speaking about two different cases. I speak about overlays (one open at a time with faded background) and you speak about popups (like real popups). This is what I would do http://jsfiddle.net/uEPBr/ . Does this work for you? – Jonas Grumann Jul 11 '14 at 12:39
1

You'd better go with something like this. Just give an id to the div which you want to hide and make a function like this. call this function by adding onclick event on body.

function myFunction(event) { 

if(event.target.id!="target_id")
{ 
    document.getElementById("target_id").style.display="none";
  }
}
anuj152
  • 11
  • 2
1

Add a transparent background taking up the whole window size, just before your popup div

.transparent-back{
    position: fixed;
    top: 0px;
    left:0px;
    width: 100%;
    height: 100%;
    background-color: rgba(255,255,255,0.5);
}

Then on its click, dismiss the popup.

$(".transparent-back").on('click',function(){
    $('popup').fadeOut(300);
});
Rajat Talwar
  • 11,922
  • 1
  • 18
  • 12
  • 2
    this works best with a modal window, but with a context menu for example, or a sliding panel, you don't want to cancel the first click outside the div as this goes against usability. – Emile Bergeron Mar 16 '16 at 00:39
  • I used a color picker div window as a popup menu and users can click on any color in the grid, if they click outside it the popup color picker just goes away and that's a really cool behavior. – alexventuraio Jan 31 '21 at 21:42
0

This question might have been answered here. There might be some potential issues when event propagation is interrupted, as explained by Philip Walton in this post.

A better approach/solution would be to create a custom jQuery event, e.g. clickoutside. Ben Alman has a great post (here) that explains how to implement one (and also explains how special events work), and he's got a nice implementation of it (here).

More reading on jQuery events API and jQuery special events:

Community
  • 1
  • 1
0
var modal = document.getElementById("reject-popup");    
window.onclick = function (event) {
    if (event.target == modal) {
        modal.style.display = "none";
    }

}
chandresh
  • 1
  • 1
-1
 //for closeing the popover when user click outside it will close all popover 
 var hidePopover = function(element) {
        var elementScope = angular.element($(element).siblings('.popover')).scope().$parent;
        elementScope.isOpen = false;
        elementScope.$apply();
        //Remove the popover element from the DOM
        $(element).siblings('.popover').remove();
    };
 $(document).ready(function(){
 $('body').on('click', function (e) {
       $("a").each(function () {
                    //Only do this for all popovers other than the current one that cause this event
           if (!($(this).is(e.target) || $(this).has(e.target).length > 0) 
                && $(this).siblings('.popover').length !== 0 && $(this).siblings('.popover').has(e.target).length === 0)                  
                    {
                         hidePopover(this);
                    }
        });
    });
 });