Close a Twitter Bootstrap Popover when Clicking Outside

A vexing topic for me and a bunch of other people on stackoverflow, the problem being that Twitter Bootstrap Popovers don’t close when you click outside to anywhere else on the document.

This might not be your desired outcome, simply: when clicking outside a popover, wouldn’t you want it to close?

The code below makes this possible:

$('[data-toggle="popover"]').popover();

$('body').on('click', function (e) {
    $('[data-toggle="popover"]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
        }
    });
});

A note about the use of $(':not(#anything)') as my body selector. This is due to iOS not binding click events to ‘html’ or ‘body’.

To put it short, this is a bulletproof way to detect clicks anywhere on the document (providing you don’t have a div with an id of ‘anything’).

Live Example Here

This entry was posted in Bootstrap, Code. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

27 Comments

  1. Posted May 19, 2013 at 7:45 pm | Permalink

    Thumbs up!

    I am working on a small addon code using Twitter Bootstrap Popover inside a Carousel. And this function works well.

    Thanks for this!

  2. Posted May 19, 2013 at 8:56 pm | Permalink

    Glad it was helpful!

  3. Rq Bukhari
    Posted May 28, 2013 at 3:10 am | Permalink

    Working awesome. Thanks for saving my time. :)
    Keep it up.

  4. ron
    Posted May 30, 2013 at 8:27 am | Permalink

    i dont really know what I’m doing javascript wise, but I tweaked your script because when i clicked on a link the page would scroll to the top. whatever i did below stopped that behavior.

    $('a[data-toggle=popover]')
    .popover();

    $(':not(#anywhereonthepage)').click(function(e)

    { e.preventDefault()

    $('a[data-toggle=popover]').each(function ()

    {

    if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('a[data-toggle=popover]').has(e.target).length === 0)
    {
    $(this).popover('hide');
    return;
    }
    });
    });

  5. Tim
    Posted June 18, 2013 at 12:06 pm | Permalink

    This was very helpful, thanks very much.

    If using fake selectors isn’t your thing, you could use the popover plugin’s data-container attribute to have the popovers appended to some container, such as #popoverContainer, and then use $(‘:not(#popoverContainer)’) on line #1. (I haven’t tried that on iOS.)

  6. Posted June 26, 2013 at 8:20 am | Permalink

    This was very helpful. Thanks!

  7. Mahmoud
    Posted June 26, 2013 at 11:53 pm | Permalink

    Thank you!

  8. Leonardo Venoso
    Posted July 19, 2013 at 9:39 am | Permalink

    This is excelent man!!! I tested it on desktop and Iphone and worked very good!!!

  9. Posted July 22, 2013 at 7:39 pm | Permalink

    Great code! Thank you!

  10. Lodewyk Duminy
    Posted July 25, 2013 at 8:39 am | Permalink

    Brilliant.

    Instantly did exactly what I needed it to do.

  11. Nassim
    Posted August 9, 2013 at 4:00 am | Permalink

    Very useful. Thanks!

  12. manish mukherjee
    Posted August 9, 2013 at 2:39 pm | Permalink

    woohoo! this was driving me crazy. i have no idea why those otherwise brilliant bootstrap people would have such a silly default behavior for the popovers.

    thanks!

  13. Ruben Trancoso
    Posted August 28, 2013 at 7:18 am | Permalink

    Hi,
    thanks by the code. I’m using it on a button placed over a nav-bar (bs3). I have noticed that differently than when the popover is closed by the link/button that opened it, the popover(‘hide’) keep it hide but live. In my case, I changed the z-order on the popover to have it over the navbar. So, when its hidden, the menu options stay inacessible! :/
    I1m trying to undertand it better. I’ll return to this…’

  14. Burak
    Posted August 29, 2013 at 7:12 am | Permalink

    Thank you…

  15. Subodh
    Posted October 7, 2013 at 2:35 am | Permalink

    Great it worked perfectly

  16. Yuri
    Posted October 9, 2013 at 1:25 pm | Permalink

    Thank you very much comrade!

  17. Lawrence Kesteloot
    Posted October 23, 2013 at 10:44 am | Permalink

    Worked great, thanks for posting this!

  18. JW
    Posted October 29, 2013 at 9:24 pm | Permalink

    Super helpful, thanks so much!

  19. Posted November 6, 2013 at 8:33 am | Permalink

    Thx! Very usefull!

  20. bnuhero
    Posted November 21, 2013 at 5:36 pm | Permalink

    It works like a charm.

  21. Posted January 18, 2014 at 7:09 am | Permalink

    I really like your blog.. very nice colors & theme.

    Did you create this website yourself or did you hire someone to do it for you?

    Plz answer back as I’m looking to construct my own blog and would like to know where u got
    this from. thanks a lot

  22. Dante
    Posted February 14, 2014 at 1:04 am | Permalink

    Hi, very thank you for this solution.

    One problems found:

    The popover panel seems to just became invisible rather than hidden after it’s dismissed by clicking outside, try the following fiddle to see the problem.

    http://jsfiddle.net/C5GBU/67/

    Click the third red button first, dismiss the popover by clicking outside of it, then the first two buttons can not be clicked because they’re blocked by the invisible popover panel.

  23. Posted February 18, 2014 at 1:59 pm | Permalink

    Seems to be a problem with bootstrap, as you can see the code uses the popover.hide method… Thank you for shining a light on this, perhaps file a bug with the bootstrap folks.

  24. Posted April 30, 2014 at 8:07 am | Permalink

    This was perfect except for one thing- the ‘hide’ method didn’t work because the container div ‘.popover’ was still in the DOM, just invisible now. It was covering/blocking the elements below it so they couldn’t be clicked. I modified your solution to remove those elements from DOM display:

    $('body').on('click', function (e) {
    //hide popover from dom to prevent covering elements
    $('.popover').css('display', 'none');
    //bring popover back if trigger element is clicked
    $('[data-toggle="popover"]').each(function () {
    if ($(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
    $('.popover').css('display', 'block');
    }
    });
    //hide popover with .popover method
    $('[data-toggle="popover"]').each(function () {
    //the 'is' for buttons that trigger popups
    //the 'has' for icons within a button that triggers a popup
    if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
    $(this).popover('hide');
    }
    });
    });

    There may be a more efficient way to remove those blocking divs, but this works.

  25. Posted August 19, 2014 at 12:57 am | Permalink

    Oh my goodness! Amazing article dude! Many thanks, However I am experiencing problems with your RSS.

    I don’t understand why I cannot subscribe to it. Is there anyone else getting similar RSS problems?
    Anyone who knows the solution will you kindly respond?

    Thanx!!

  26. Posted April 16, 2015 at 11:59 pm | Permalink

    working excellently. thank you verymuch

  27. Phil
    Posted May 7, 2015 at 1:47 pm | Permalink

    Perfect, and to the point. Thank you very much.

3 Trackbacks

Post a Comment

Your email is never published nor shared. Required fields are marked *

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*
*