122

I have a jQuery UI Dialog that gets displayed when specific elements are clicked. I would like to close the dialog if a click occurs anywhere other than on those triggering elements or the dialog itself.

Here's the code for opening the dialog:

$(document).ready(function() {
    var $field_hint = $('<div></div>')
        .dialog({
            autoOpen: false,
            minHeight: 50,
            resizable: false,
            width: 375
        });

    $('.hint').click(function() {
        var $hint = $(this);
        $field_hint.html($hint.html());
        $field_hint.dialog('option', 'position', [162, $hint.offset().top + 25]);
        $field_hint.dialog('option', 'title', $hint.siblings('label').html());
        $field_hint.dialog('open');
    });
    /*$(document).click(function() {
        $field_hint.dialog('close');
    });*/
});

If I uncomment the last part, the dialog never opens. I assume it's because the same click that opens the dialog is closing it again.


Final Working Code
Note: This is using the jQuery outside events plugin

$(document).ready(function() {
    // dialog element to .hint
    var $field_hint = $('<div></div>')
            .dialog({
                autoOpen: false,
                minHeight: 0,
                resizable: false,
                width: 376
            })
            .bind('clickoutside', function(e) {
                $target = $(e.target);
                if (!$target.filter('.hint').length
                        && !$target.filter('.hintclickicon').length) {
                    $field_hint.dialog('close');
                }
            });

    // attach dialog element to .hint elements
    $('.hint').click(function() {
        var $hint = $(this);
        $field_hint.html('<div style="max-height: 300px;">' + $hint.html() + '</div>');
        $field_hint.dialog('option', 'position', [$hint.offset().left - 384, $hint.offset().top + 24 - $(document).scrollTop()]);
        $field_hint.dialog('option', 'title', $hint.siblings('label').html());
        $field_hint.dialog('open');
    });

    // trigger .hint dialog with an anchor tag referencing the form element
    $('.hintclickicon').click(function(e) {
        e.preventDefault();
        $($(this).get(0).hash + ' .hint').trigger('click');
    });
});
Sonny
  • 8,204
  • 7
  • 63
  • 134

21 Answers21

168

Sorry to drag this up after so long but I used the below. Any disadvantages? See the open function...

$("#popup").dialog(
{
    height: 670,
    width: 680,
    modal: true,
    autoOpen: false,
    close: function(event, ui) { $('#wrap').show(); },
    open: function(event, ui) 
    { 
        $('.ui-widget-overlay').bind('click', function()
        { 
            $("#popup").dialog('close'); 
        }); 
    }
});
Lee Taylor
  • 7,761
  • 16
  • 33
  • 49
stumac85
  • 2,057
  • 2
  • 13
  • 9
  • 18
    Actually this will only work if the UI window is modal. Well useful if you want to shut a modal dialog – stumac85 Dec 01 '10 at 15:07
  • 39
    Very nice. I just changed it to this so I didn't have to set the ID reference explicitly: `$('.ui-widget-overlay').bind('click', function () { $(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close'); });` – James McCormack Dec 02 '11 at 10:33
  • 1
    I like this one. Is there a case where you don't want it modal but still want click outside to close? Doesn't make sense to me (I guess with modal you lose hovering on outside/underneath elements). – Nick Spacek Jan 18 '12 at 14:12
  • 3
    @NickSpacek - When it's not modal I can set focus to a field, open a new dialog, etc. with only one click. With a modal dialog I would have to use two clicks: one to close it, and one to do the next action. – Sonny Mar 01 '12 at 17:26
  • 1
    Thanks! You can also take advantage of jQuery live bubbling. $('body').on('click', '.ui-widget-overlay', close); – Quang Van Dec 06 '12 at 19:06
  • @Sonny I personally don't like that UI design anyway. If clicking outside the popup closes it, I wouldn't expect any links or buttons I happened to click on to fire their events. I would actually be pretty annoyed with that behavior. – Katie Kilian Dec 31 '12 at 20:30
  • @CharlieKilian - That's the way non-modal dialogs work. There's no overlay, so the expectation is that whatever you click on is actionable. I understand the difference in opinion between modal and non-modal, so I am glad that both solutions are here. – Sonny Jan 01 '13 at 20:02
  • It works for me without the autoOpen: false - Thanks! – Yster Aug 27 '14 at 10:00
  • wow thanks man, work like a charm ..though I am implementing when mouse hover outside the dialog. – Kunchok Tashi Apr 21 '20 at 17:48
  • @stumac85 of course, it is declared as a modal dialog..... – Jean G.T Aug 05 '21 at 20:20
83

Forget using another plugin:

Here are 3 methods to close a jquery UI dialog when clicking outside popin:

If the dialog is modal/has background overlay: http://jsfiddle.net/jasonday/6FGqN/

jQuery(document).ready(function() {
    jQuery("#dialog").dialog({
        bgiframe: true,
        autoOpen: false,
        height: 100,
        modal: true,
        open: function(){
            jQuery('.ui-widget-overlay').bind('click',function(){
                jQuery('#dialog').dialog('close');
            })
        }
    });
}); 

If dialog is non-modal Method 1: method 1: http://jsfiddle.net/jasonday/xpkFf/

 // Close Pop-in If the user clicks anywhere else on the page
                     jQuery('body')
                      .bind(
                       'click',
                       function(e){
                        if(
                         jQuery('#dialog').dialog('isOpen')
                         && !jQuery(e.target).is('.ui-dialog, a')
                         && !jQuery(e.target).closest('.ui-dialog').length
                        ){
                         jQuery('#dialog').dialog('close');
                        }
                       }
                      );

Non-Modal dialog Method 2: http://jsfiddle.net/jasonday/eccKr/

  $(function() {
            $( "#dialog" ).dialog({
                autoOpen: false, 
                minHeight: 100,
                width: 342,
                draggable: true,
                resizable: false,
                modal: false,
                closeText: 'Close',
                  open: function() {
                      closedialog = 1;
                      $(document).bind('click', overlayclickclose);
                  },
                  focus: function() {
                      closedialog = 0;
                  },
                  close: function() {
                      $(document).unbind('click');
                  }



        });

         $('#linkID').click(function() {
            $('#dialog').dialog('open');
            closedialog = 0;
        });

         var closedialog;

          function overlayclickclose() {
              if (closedialog) {
                  $('#dialog').dialog('close');
              }

              //set to one because click on dialog box sets to zero
              closedialog = 1;
          }


  });
Jason
  • 7,612
  • 14
  • 77
  • 127
  • 2
    Great! I slightly changed the open option function for modal dialog, so there is no need to explicitly name the element. `open : function () { $('.ui-widget-overlay').on('click', function () { $(this).parents("body").find(".ui-dialog-content").dialog("close"); }); }` – meridius May 30 '13 at 12:51
  • Note that for solution #2, .is('.ui-dialog, a') has to be changed to .is('.ui-dialog, whateverYouClickOnToOpenTheDialog') – personne3000 Nov 24 '13 at 23:34
  • @Jason because of the comma, I think this line is actually saying "not the ui-dialog, or any link in the page". If I change the "Open dialog" link in your example to a , the dialog is closed immediately after opening as the window event is triggered last, which is why I think you need to exclude the item you click on to open the dialog. I don't understand why you would need to reference links in the dialog ? – personne3000 Nov 25 '13 at 10:08
  • @personne3000 - actually you're right about the context, that the selector is choosing both. I'm trying to remember why I added that in, as I must have had a specific reason that I'm not remembering at the moment. – Jason Nov 26 '13 at 00:27
  • @Jason to avoid conflicts with multiple dialogs you can use namespaced events `click.myNamespace` – Christophe Roussy Mar 27 '14 at 12:09
  • As @Jerph suggested, to have method 1 working I had to call `stopPropagation` to avoid closing dialogs as soon as they get opened – Sue Maurizio Dec 22 '14 at 08:03
  • I suggest to bind to `html` instead of `body` in method 1 of non-modal dialog. Instead of `jQuery('body').bind(...` Use `jQuery('html').bind(...` 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. So clicks below the body would be ignored. – huha Oct 08 '15 at 06:58
  • I love the purity of Non-modal method #1 — Just had to call `event.stopPropagation();` in the function that opens the dialog, to keep it from immediately closing. – ElmerCat Feb 01 '18 at 07:38
32

Check out the jQuery Outside Events plugin

Lets you do:

$field_hint.bind('clickoutside',function(){
    $field_hint.dialog('close');
});
PetersenDidIt
  • 25,562
  • 3
  • 67
  • 72
  • I'm getting the same behavior, in that the hint won't display when the $('.hint') elements are clicked. Those elements are 'outside' the dialog. – Sonny Mar 31 '10 at 16:59
  • You only care about the click outside if the dialog is open. So only bind it after you open it. – PetersenDidIt Mar 31 '10 at 17:07
  • 3
    I read in another place about filtering based in the event, and that solved the problem: http://groups.google.com/group/jquery-ui/msg/a880d99138e1e80d – Sonny Mar 31 '10 at 17:08
  • The dialog gets reused several times in the document, so I'd have to have a way to unbind when closing the dialog. I think the filtering is a simpler solution. – Sonny Mar 31 '10 at 17:12
18

Just add this global script, which closes all the modal dialogs just clicking outsite them.

$(document).ready(function()
{
    $(document.body).on("click", ".ui-widget-overlay", function()
    {
        $.each($(".ui-dialog"), function()
        {
            var $dialog;
            $dialog = $(this).children(".ui-dialog-content");
            if($dialog.dialog("option", "modal"))
            {
                $dialog.dialog("close");
            }
        });
    });;
});
Michele Locati
  • 1,655
  • 19
  • 25
  • I am not using a modal dialog. The answer here with the most up-votes is also for modal dialogs. – Sonny Aug 24 '12 at 12:28
  • When using the same dialog more than once on the same page this is the only way to go as it will only work once if you bind it in the open function. Thanks for this great idea! – MaDaHoPe Aug 03 '16 at 23:26
  • here's mine: `$(document).on('click', '.ui-widget-overlay', function() { $('#'+$('.ui-dialog-content')[0].id).dialog('close'); });` – mr5 Dec 12 '17 at 16:38
12
$(".ui-widget-overlay").click (function () {
    $("#dialog-id").dialog( "close" );
});

Fiddle showing the above code in action.

jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
jk.
  • 14,365
  • 4
  • 43
  • 58
8

I had to do two parts. First the outside click-handler:

$(document).on('click', function(e){
    if ($(".ui-dialog").length) {
        if (!$(e.target).parents().filter('.ui-dialog').length) {
            $('.ui-dialog-content').dialog('close');
        }
    }
}); 

This calls dialog('close') on the generic ui-dialog-content class, and so will close all dialogs if the click didn't originate in one. It will work with modal dialogs too, since the overlay is not part of the .ui-dialog box.

The problem is:

  1. Most dialogs are created because of clicks outside of a dialog
  2. This handler runs after those clicks have created a dialog and bubbled up to the document, so it immediately closes them.

To fix this, I had to add stopPropagation to those click handlers:

moreLink.on('click', function (e) {
    listBox.dialog();
    e.stopPropagation(); //Don't trigger the outside click handler
});
Jerph
  • 4,572
  • 3
  • 42
  • 41
  • This sounds simpler than the solution I am using. I will have to try it out. – Sonny Dec 12 '11 at 13:45
  • This is the solution I thought of myself, but mine is a one-liner: `$('body').on('click', '.ui-widget-overlay', function () { $('#myDialog').dialog('close'); });` – styfle Jan 04 '13 at 19:50
5

This question is a bit old, but in case someone wants to close a dialog that is NOT modal when user clicks somewhere, you can use this that I took from the JQuery UI Multiselect plugin. The main advantage is that the click is not "lost" (if user wants to click on a link or a button, the action is done).

$myselector.dialog({
            title: "Dialog that closes when user clicks outside",
            modal:false,
            close: function(){
                        $(document).off('mousedown.mydialog');
                    },
            open: function(event, ui) { 
                    var $dialog = $(this).dialog('widget');
                    $(document).on('mousedown.mydialog', function(e) {
                        // Close when user clicks elsewhere
                        if($dialog.dialog('isOpen') && !$.contains($myselector.dialog('widget')[0], e.target)){
                            $myselector.dialog('close');
                        }            
                    });
                }                    
            });
Melanie
  • 1,198
  • 2
  • 17
  • 42
  • I had to move `var $dialog = $(this).dialog('widget');` inside the on-click event handler – Stefan Haberl Feb 05 '14 at 21:34
  • 1
    @Melanie, I think your solution is more applicable, than others. One guy created plugin for 'jqui dialog' based on your approach - [js at github](https://github.com/coheractio/jQuery-UI-Dialog-ClickOutside/blob/master/ui-clickoutside/jquery.ui.dialog-clickoutside.js) – resnyanskiy Apr 01 '15 at 07:52
5

You can do this without using any additional plug-in

var $dialog= $(document.createElement("div")).appendTo(document.body);
    var dialogOverlay;

    $dialog.dialog({
        title: "Your title",
        modal: true,
        resizable: true,
        draggable: false,
        autoOpen: false,
        width: "auto",
        show: "fade",
        hide: "fade",
        open:function(){
            $dialog.dialog('widget').animate({
                width: "+=300", 
                left: "-=150"
            });

//get the last overlay in the dom
            $dialogOverlay = $(".ui-widget-overlay").last();
//remove any event handler bound to it.
            $dialogOverlay.unbind();
            $dialogOverlay.click(function(){
//close the dialog whenever the overlay is clicked.
                $dialog.dialog("close");
            });
        }
    });

Here $dialog is the dialog. What we are basically doing is to get the last overlay widget whenever this dialog is opened and binding a click handler to that overlay to close $dialog as anytime the overlay is clicked.

GuruKay
  • 3,429
  • 2
  • 20
  • 8
  • I think this is similar to other solutions for a modal dialog. My question was for non-modal dialogs. – Sonny Jun 19 '13 at 15:44
5

no need for the outside events plugin...

just add an event handler to the .ui-widget-overlay div:

jQuery(document).on('click', 'body > .ui-widget-overlay', function(){
     jQuery("#ui-dialog-selector-goes-here").dialog("close");
     return false;
});

just make sure that whatever selector you used for the jQuery ui dialog, is also called to close it.. i.e. #ui-dialog-selector-goes-here

Jonathan Marzullo
  • 6,879
  • 2
  • 40
  • 46
  • Several solutions for closing modal dialogs have been proposed already. My dialog is non-modal, and therefore has no overlay. – Sonny Aug 20 '13 at 18:51
  • Than you simply just bind the click event to the body tag or div wrapper and use that as your click event trigger, instead of the modal. – Jonathan Marzullo Mar 25 '14 at 16:41
  • Yes. That's essentially what my solution does. It also has to exclude clicks within the dialog. – Sonny Mar 26 '14 at 14:59
3

This doesn't use jQuery UI, but does use jQuery, and may be useful for those who aren't using jQuery UI for whatever reason. Do it like so:

function showDialog(){
  $('#dialog').show();
  $('*').on('click',function(e){
    $('#zoomer').hide();
  });
}

$(document).ready(function(){

  showDialog();    

});

So, once I've shown a dialog, I add a click handler that only looks for the first click on anything.

Now, it would be nicer if I could get it to ignore clicks on anything on #dialog and its contents, but when I tried switching $('*') with $(':not("#dialog,#dialog *")'), it still detected #dialog clicks.

Anyway, I was using this purely for a photo lightbox, so it worked okay for that purpose.

Aamir
  • 5,324
  • 2
  • 30
  • 47
Volomike
  • 23,743
  • 21
  • 113
  • 209
2

The given example(s) use one dialog with id '#dialog', i needed a solution that close any dialog:

$.extend($.ui.dialog.prototype.options, {
    modal: true,
    open: function(object) {
        jQuery('.ui-widget-overlay').bind('click', function() {              
            var id = jQuery(object.target).attr('id');
            jQuery('#'+id).dialog('close');
        })
    }
});

Thanks to my colleague Youri Arkesteijn for the suggestion of using prototype.

2

This is the only method that worked for me for my NON-MODAL dialog

$(document).mousedown(function(e) {
    var clicked = $(e.target); // get the element clicked
    if (clicked.is('#dlg') || clicked.parents().is('#dlg') || clicked.is('.ui-dialog-titlebar')) {
        return; // click happened within the dialog, do nothing here
    } else { // click was outside the dialog, so close it
        $('#dlg').dialog("close");
    }
});

All credit goes to Axle
Click outside non-modal dialog to close

Community
  • 1
  • 1
Colin
  • 1,758
  • 1
  • 19
  • 24
1

For those you are interested I've created a generic plugin that enables to close a dialog when clicking outside of it whether it a modal or non-modal dialog. It supports one or multiple dialogs on the same page.

More information here: http://www.coheractio.com/blog/closing-jquery-ui-dialog-widget-when-clicking-outside

Laurent

Laurent
  • 440
  • 1
  • 4
  • 11
1

I use this solution based in one posted here:

var g_divOpenDialog = null;
function _openDlg(l_d) {

  // http://stackoverflow.com/questions/2554779/jquery-ui-close-dialog-when-clicked-outside
  jQuery('body').bind(
   'click',
   function(e){
    if(
      g_divOpenDialog!=null 
      && !jQuery(e.target).is('.ui-dialog, a')
      && !jQuery(e.target).closest('.ui-dialog').length
    ){
      _closeDlg();
    }
   }
  );

  setTimeout(function() {
    g_divOpenDialog = l_d;
    g_divOpenDialog.dialog();
  }, 500);
}
function _closeDlg() {
  jQuery('body').unbind('click');
  g_divOpenDialog.dialog('close');
  g_divOpenDialog.dialog('destroy');
  g_divOpenDialog = null;
}
Alejo
  • 11
  • 1
1

I had same problem while making preview modal on one page. After a lot of googling I found this very useful solution. With event and target it is checking where click happened and depending on it triggers the action or does nothing.

Code Snippet Library site

$('#modal-background').mousedown(function(e) {
var clicked = $(e.target);  
if (clicked.is('#modal-content') || clicked.parents().is('#modal-content')) 
    return; 
} else {  
 $('#modal-background').hide();
}
});
0

İt's simple actually you don't need any plugins, just jquery or you can do it with simple javascript.

$('#dialog').on('click', function(e){
  e.stopPropagation();
});
$(document.body).on('click', function(e){
  master.hide();
});
Brandon
  • 68,708
  • 30
  • 194
  • 223
0

I don't think finding dialog stuff using $('.any-selector') from the whole DOM is so bright.

Try

$('<div />').dialog({
    open: function(event, ui){
        var ins = $(this).dialog('instance');
        var overlay = ins.overlay;
        overlay.off('click').on('click', {$dialog: $(this)}, function(event){
            event.data.$dialog.dialog('close');
        });
    }
});

You're really getting the overlay from the dialog instance it belongs to, things will never go wrong this way.

badboy
  • 106
  • 2
0

With the following code, you can simulate a click on the 'close' button of the dialog (change the string 'MY_DIALOG' for the name of your own dialog)

$("div[aria-labelledby='ui-dialog-title-MY_DIALOG'] div.ui-helper-clearfix a.ui-dialog-titlebar-close")[0].click();
perkas
  • 48
  • 6
0

Smart Code: I am using following code so that every thing remains clear and readable. out side body will close the dialog box.

$(document).ready(function () {
   $('body').on('click', '.ui-widget-overlay', closeDialogBox);
});

function closeDialogBox() {
    $('#dialog-message').dialog('close');
}
Farid Abbas
  • 294
  • 4
  • 5
0

I ended up using this code which should work on any open dialogs on the page, ignores clicks on tooltips, and cleans up the resources of the dialog being closed as well.


        $(document).mousedown(function(e) {
            var clicked = $(e.target); // get the element clicked
            if (clicked.is('.ui-dialog-content, .ui-dialog-titlebar, .ui-tooltip') || clicked.parents().is('.ui-dialog-content, .ui-dialog-titlebar, .ui-tooltip')) {
                return; // click happened within the dialog, do nothing here
            } else { // click was outside the dialog, so close it
                $('.ui-dialog-content').dialog("close");
                $('.ui-dialog-content').dialog("destroy");
                $('.ui-dialog-content').detach();

            }
        });
0

I just ran across the need to close .dialog(s) with an out of element click. I have a page with a lot of info dialogs, so I needed something to handle them all. This is how I handled it:

$(document).ready(function () {    
    $(window).click(function (e) {
        $(".dialogGroup").each(function () {
            $(this).dialog('close');
        })
    });
    $("#lostEffClick").click(function () {
        event.stopPropagation();
        $("#lostEffDialog").dialog("open");
    };
});