50

How can I close an open collapsed navbar on clicking outside of the navbar element? Currently, the only way to open or close it is by clicking on the navbar-toggle button.

See here for an example and code:

So far, I have tried the following which doesn't seem to work:

jQuery(document).click(function() {

});

jQuery('.navbar').click(function(event) {
    jQuery(".navbar-collapse").collapse('hide');
    event.stopPropagation();
});
Jordan.J.D
  • 7,999
  • 11
  • 48
  • 78
henrywright
  • 10,070
  • 23
  • 89
  • 150
  • The 'broken' link in the demo closes when I click outside of the menu; what is broken? – Dmitry Sadakov May 20 '14 at 16:08
  • @Paulie_D I've updated my question with what I've tried. – henrywright May 20 '14 at 16:10
  • @cDima what broken link are you referring to? I don't see one. – henrywright May 20 '14 at 16:11
  • I'm assuming he means the 'hamburger' element opens the menu at the appropriate width and re-clicking closes it. I assume he wants the same 'close' to take place when clicking anywhere. – Paulie_D May 20 '14 at 16:13
  • So just selecting the `body` in your JQuery function should do it, assuming to check to see if THE MENU IS OPEN. – Paulie_D May 20 '14 at 16:14
  • The check to see if the menu is open is the part i'm struggling with. Currently, the menu opens and closes when I click outside of the navbar element. I'd like it to just close IF it is already open – henrywright May 20 '14 at 16:20

17 Answers17

54

Have a look that:

$(document).ready(function () {
    $(document).click(function (event) {
        var clickover = $(event.target);
        var _opened = $(".navbar-collapse").hasClass("navbar-collapse in");
        if (_opened === true && !clickover.hasClass("navbar-toggle")) {
            $("button.navbar-toggle").click();
        }
    });
});

Your fiddle works with that: http://jsfiddle.net/52VtD/5718/

Its a modified version of this answer, which lacks the animation and is also a tiny bit more complicated.

I know, invoking the click() isn't very elegant, but collapse('hide') did not work for me either, and i think the animation is a bit nicer than adding and removing the classes hardly.

Community
  • 1
  • 1
nozzleman
  • 9,529
  • 4
  • 37
  • 58
  • Yeah, I'm not sure why `collapse('hide)` isn't working. This solution works perfectly though. – henrywright May 20 '14 at 21:02
  • 1
    It won't work if the navbar contains a search box, clicking on the search text input must not close the navbar: http://jsfiddle.net/duongphuhiep/xtyb6wwu/1/ – Hiep Aug 17 '15 at 00:15
  • 9
    For whatever reason I needed this on the latest bootstrap 3: .hasClass("navbar-collapse collapse in") – davidethell Oct 30 '15 at 19:34
  • this is very good working when using in angularJS and ui-router. it is very fine to use it on $stateChangeSuccess – Ebrahim Jul 23 '16 at 09:45
  • If using Aurelia you can use it this way `this.eventAggregator.subscribe('router:navigation:success', response => { jQuery("navigation button.navbar-toggle").click(); });` – user1127860 Oct 31 '17 at 09:54
  • I am not sure is `click()` will work on mobiles, where this menu is used. – gdfgdfg Nov 26 '19 at 02:14
44

The accepted answer doesn't appear to work correctly. It only needs to check if "navbar-collapse" has the "in" class. We can then fire the collapse method as expected by using our reference to the navbar.

$(document).click(function (event) {
    var clickover = $(event.target);
    var $navbar = $(".navbar-collapse");               
    var _opened = $navbar.hasClass("in");
    if (_opened === true && !clickover.hasClass("navbar-toggle")) {      
        $navbar.collapse('hide');
    }
});
Paul Tarr
  • 498
  • 4
  • 10
28

Using this works for me.

$(function() {
  $(document).click(function (event) {
    $('.navbar-collapse').collapse('hide');
  });
});
Shiva Charan
  • 307
  • 3
  • 4
17

The solution I decided to use was taken from the accepted answer here and from this answer

jQuery('body').bind('click', function(e) {
    if(jQuery(e.target).closest('.navbar').length == 0) {
        // click happened outside of .navbar, so hide
        var opened = jQuery('.navbar-collapse').hasClass('collapse in');
        if ( opened === true ) {
            jQuery('.navbar-collapse').collapse('hide');
        }
    }
});

This hides an opened collapsed nav menu if the user clicks anywhere outside of the .navbar element. Of course clicking on .navbar-toggle still works to close the menu too.

Community
  • 1
  • 1
henrywright
  • 10,070
  • 23
  • 89
  • 150
  • I would change `body` to `html` to account for tall devices or pages with little content. The body's height matches the content, rather than the visible screen area, so if you have a page with little content, taps below the content area won't trigger. Otherwise a great answer and works really well, even with navbar submenus. – Amy Barrett Jan 17 '17 at 17:12
  • 1
    works beautifully. To make it close for any click other than the menu itself and the navbar-toggle button, just replace the first ".navbar" with ".navbar-collapse" so that even if you click other links in the navbar, it will still close the menu. – Rachel S Jul 19 '17 at 16:05
  • I had to remove 'in' class from hasClass check, without which it was not working. May be because I did not have an 'in' class in my .navbar-collapse element. I am using bootstrap 4. – Anurag Jul 08 '20 at 10:42
12

Converted nozzleman's answer for Bootstrap 4(.3.1):

$(document).ready(function () {
    $(document).click(
        function (event) {
            var target = $(event.target);
            var _mobileMenuOpen = $(".navbar-collapse").hasClass("show");
            if (_mobileMenuOpen === true && !target.hasClass("navbar-toggler")) {
                $("button.navbar-toggler").click();
            }
        }
    );
});

Placed in the ngOnInit().

When the document is loaded, this code waits for click events. If the mobile menu dropdown is open (i.e. the collapsible part of the navbar has the "show" class) and the clicked object (target) is not the mobile menu button (i.e. does not have the "navbar-toggler" class), then we tell the mobile menu button it has been clicked, and the menu closes.

Kale
  • 413
  • 1
  • 5
  • 12
4

stopPropagation() is not always the best solution. Rather use something like:

jQuery(document.body).on('click', function(ev){
    if(jQuery(ev.target).closest('.navbar-collapse').length) return; // Not return false

    // Hide navbar
});

I think it's dangerous to assume that you never want to listen to any other event from the .navbar. Which is impossible if you use stopPropagation().

pstenstrm
  • 6,339
  • 5
  • 41
  • 62
  • Hi @pstenstrm. thanks for this although it doesn't seem to work? I've updated the JSFIDDLE with your jQuery: http://jsfiddle.net/52VtD/5708/ – henrywright May 20 '14 at 16:56
  • Well, the `.navbar` is pretty much the entire document in the fiddle. I've updated my answer – pstenstrm May 20 '14 at 17:07
  • Point noted! I've given the body a height of 700px so the jsfiddle better illustrates what is happening: http://jsfiddle.net/52VtD/5709/ - the problem now is clicking in the body both closes and opens the dropdown. I need it to close only. Opening should be done only via the toggle button `navbar-toggle` – henrywright May 20 '14 at 17:19
3

I had a scenario where I had plain text and I didn't want the panel to close if a user clicks on the plain text on accident. The other answers here will close the panel even if you click on the text of an item that isn't a link.

To fix this I added on to Paul Tarr's answer by wrapping the solution in a check to see whether or not the click occurred anywhere inside:

if ($(event.target).parents(".navbar-collapse").length < 1) { }

The full code would become:

$(document).click(function (event) {
if ($(event.target).parents(".navbar-collapse").length < 1) {
    var clickover = $(event.target);
    var $navbar = $(".navbar-collapse");               
    var _opened = $navbar.hasClass("in");
    if (_opened === true && !clickover.hasClass("navbar-toggle")) {      
        $navbar.collapse('hide');
    }
  }
});

In this demo fiddle you can see that if you click on a non-link inside of the panel it won't collapse it.

maxshuty
  • 9,708
  • 13
  • 64
  • 77
2

For latest Bootstrap, this is the correct answer.

$(document).click(function (event) {
    var clickover = $(event.target);
    var $navbar = $(".navbar-collapse");               
    var _opened = $navbar.hasClass("show");
    if (_opened === true && !clickover.hasClass("navbar-toggler")) {      
        $navbar.collapse('hide');
    }
});

It reads if .navbar-collapse has the word show in classes (which means menu is opened) and hides the navbar when you click/tap anywhere.

gerstavros
  • 39
  • 6
2

Vanilla Javascript.

Working on Bootstrap 5.2.

window.onload = function () {
    document.addEventListener("click", function (event) {
        // if the clicked element isn't child of the navbar, you must close it if is open
        if (!event.target.closest("#navbar_id") && document.getElementById("navbarSupportedContent").classList.contains("show")) {
            document.getElementById("hamburger_menu_button").click();
        }
    });
}

https://jsfiddle.net/j4tgpbxz/

You just need to add an id to the navbar element, and then check if the clicked element is a child of that same navbar and the content you want to hide (dropdown) is being shown.

1

I've added a condition to @nozzleman's answer to check if the tap or click has been made on any element within the menu, and if that's the case, not to collapse it.

$(document).ready(function () {
    $(document).click(function (event) {
        var clickover = $(event.target);
        var _opened = $(".navbar-collapse").hasClass("navbar-collapse in");
        if (_opened === true && !clickover.hasClass("navbar-toggle") && clickover.parents('.navbar-collapse').length == 0) {
            $("button.navbar-toggle").click();
        }
    });
});
sonxurxo
  • 5,648
  • 2
  • 23
  • 33
1

The following code works for me and the advantage is that on small screens, it does not hide the .collapse when you click on its nav parent with .navbar .navbar-expand classes:

$(document).click(function (e) {  
    if($('.collapse').hasClass('show') && !$('nav').is(e.target) && $('nav').has(e.target).length === 0){
        $('.navbar-toggler').click()
    }
})
Nasim B. D
  • 161
  • 1
  • 6
0

For Bootstrap 4

Bootstrap 4 doesn't have an in class. This is Coffeescript.

  $(document).click (e)->
    #console.log e.target
    unless $('#toggle-button').has(e.target).length || $('#toggle-menu').has(e.target).length
      $('#toggle-menu').collapse('hide')

So basically, unless you click the button or the menu, close the menu.

Note: Strange, on iOS clicking on text doesn't register a click event, nor a mouseup event. Clicking on an image does fire events though.

Community
  • 1
  • 1
Chloe
  • 25,162
  • 40
  • 190
  • 357
0

For Bootstrap 4:

$(document).click(function(event) {
  $(event.target).closest(".navbar").length || $(".navbar-collapse.show").length && $(".navbar-collapse.show").collapse("hide")
});
Timur
  • 1
  • 1
0
$(document).click(function (event) {
 if ($('.navbar-collapse').attr('aria-expanded') == "true") {
        $('.navbar-collapse:visible').click();
    }
});
0
$(window).click(function (e) {
     if ($(e.target).closest('.codehim-dropdown').length) {
         return;
     }
     if ($(e.target).closest(offCanvas).length) {
         return;
     }

     //check if menu really opened
     if ($(hamburger).hasClass("active")) {
         closeMenu();
     }

     $(dimOverlay).fadeOut();

     $(".menu-items").slideUp();
     $(".dropdown-heading").removeClass("active");

});
adiga
  • 34,372
  • 9
  • 61
  • 83
muthu
  • 1
0

I had some problems with some answers here, and I would like to also be able to close the expanded menu on demand. So I did it with a simple function, and simulating the click.

function closeMenu(){
  element = document.getElementById('nav_top');
  if(element){
    if(element.classList.contains('show')){
      document.getElementById('navbar_toggler').dispatchEvent(new CustomEvent('click'));
    }
  }
}
$(document).ready(function () {
  $(document).click(function (event) {
    closeMenu();
  });
});

Using this method you can close it when clicked outside, but also you can call the closeMenu() at any time from any other function.

Cosmin Staicu
  • 1,809
  • 2
  • 20
  • 27
Andre Duarte
  • 51
  • 1
  • 5
0

I know its quite awhile for the answer. But I think the answer here could helps.

Lets say the condition: if user want to close the navbar when click outside but not when user click any element inside of the navbar

use the event.target and target the element's closest classname whether its has the navbar class or not. If yes which means user is clicking element inside of the navbar and not to close the navbar.

$(function() {
    $(document).click(function (event) {
        var clickover = $(event.target);
        var _opened = $(".navbar-collapse").hasClass("navbar-collapse collapse show");
        if (_opened === true && clickover.closest('.navbar').length === 0) {
            $(".navbar-collapse").collapse('hide');
        }
    });
});
Kopi Bryant
  • 1,300
  • 1
  • 15
  • 30