39

If the dropdown is visible, and I click outside the dropdown it closes. I need it to not close.

From the documentation:

When opened, the plugin also adds .dropdown-backdrop as a click area for closing dropdown menus when clicking outside the menu.

What JavaScript can I add to prevent the drop down from closing?

KyleMit
  • 30,350
  • 66
  • 462
  • 664
kleban
  • 529
  • 1
  • 5
  • 7

9 Answers9

104

From the events section of the Bootstrap dropdown documentation:

hide.bs.dropdown: This event is fired immediately when the hide instance method has been called.

For starters, to prevent the dropdown from closing, we can just listen to this event and stop it from proceeding by returning false:

$('#myDropdown').on('hide.bs.dropdown', function () {
    return false;
});

For a complete solution, you probably want to allow it to close when the dropdown itself is clicked. So only some of the time we'll want to prevent the box from closing.

To do this we'll set .data() flags in two more events raised by the dropdown:

  • shown.bs.dropdown - When shown, we'll set .data('closable') to false
  • click - When clicked, we'll set .data('closable') to true

Thus, if the hide.bs.dropdown event was raised by a click on the dropdown, we'll allow a close.

Live Demo in jsFiddle

JavaScript

$('.dropdown.keep-open').on({
    "shown.bs.dropdown": function() { this.closable = false; },
    "click":             function() { this.closable = true; },
    "hide.bs.dropdown":  function() { return this.closable; }
});

HTML (note I've added the class keep-open to the dropdown)

<div class="dropdown keep-open">
    <!-- Dropdown Button -->
    <button id="dLabel" role="button" href="#" class="btn btn-primary"
            data-toggle="dropdown" data-target="#" >
        Dropdown <span class="caret"></span>
    </button>

    <!-- Dropdown Menu -->
    <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
    </ul>
</div>
KyleMit
  • 30,350
  • 66
  • 462
  • 664
  • 2
    Found so many answers to that question but this one is by far the best and saved me quite some time. Thank you very much! +1 – Andresch Serj Mar 26 '14 at 14:51
  • Can you also port this solution for Bootstrap 2.x please? :-) .. I tried but not able to make it work. – VarunC May 14 '14 at 13:22
  • 1
    @VarunChaddha, You should ask another question and tag it with 2.x and link back to this one so you can show your work so far. – KyleMit May 14 '14 at 13:52
  • 2
    thnx for your reply @KyleMit. Actually I am able to get this resolved using following code: $j('.cal-options-dropdown .dropdown-menu').on({ "click":function(e){ e.stopPropagation(); } }); ... I don't know if I should open new question and answer it myself on that with this answer? – VarunC May 14 '14 at 17:35
  • 2
    I tried your jsfiddle and it doesn't seem to work. I click any of the options in the dropdown and it closes. I've tried this fix and the stopPropogation fix and none seem to keep the dropdown from closing. Any suggestions? – onetwopunch Dec 15 '14 at 20:26
  • @jryancanty, that's precisely what it's supposed to do! If you want it to *always* stay open, then use the first solution in my post. I added to that saying that `you probably want to allow it to close when the dropdown itself is clicked`, so I implemented a more complicated solution to achieve that. – KyleMit Dec 15 '14 at 20:51
  • [here](http://stackoverflow.com/a/21991258/2218697) is **another solution** to check, hope helps someone. – Shaiju T Apr 11 '16 at 06:34
  • @stom, that's pretty much the same solution. – KyleMit Apr 11 '16 at 14:24
  • For fellow UX mavericks who have set the dropdown menu to be expanded on page load, and want it to remain open until user clicks the actual menu, this hack may be useful: `"hide.bs.dropdown": function() { return (this.closable===true); }` – Ben Apr 12 '16 at 10:29
  • Great answer! What if you want to have the dropdown open the minute the page loads, without user having to click on it and then have it kept open. – Tisha May 24 '16 at 20:38
  • @Tisha, you'll want to look at [How to open Bootstrap dropdown programmatically](http://stackoverflow.com/a/35760042/1366033). You can chain `.find('.dropdown-toggle').dropdown('toggle')` after you initialize the listeners to trigger the dropdown from opening. All the other listeners can stay exactly as is. [**Demo in jsFiddle**](http://jsfiddle.net/KyleMit/ZS4L7/1465/) – KyleMit May 24 '16 at 21:19
  • I am was using **multilevel dropdown** and I probably want to allow it to close when the dropdown itself is clicked but for some reason second option didnt work for me but [this](http://stackoverflow.com/questions/21694010/keep-bootstrap-3-dropdown-open-when-clicked) worked, hope helps someone. – Shaiju T Sep 06 '16 at 10:54
  • @user1735921, how/when/why/where? That's not a sufficient bug report, even if support was guaranteed over many years. We're all programmers here. Put on your programmer hat and produce a sample, create an [MCVE] and explain where it's not working or doing what you think it should do. "it's not working" is hardly ever going to cut it, especially not here. – KyleMit Apr 06 '17 at 12:22
  • 1
    Hey, I am sorry, I didn't mean to offend, I am trying to find similar solution, but on react. Your code doesn't work on jquery too, you can see the corrections in Mike Kane's answer, that works. – user1735921 Apr 06 '17 at 17:55
  • Just implemented this solution, works on the original jsfiddle and in my own code. – HunterTheGatherer Jan 18 '19 at 06:57
18

Version changes in some dependency have caused KyleMit's, and most other solutions to no longer work. I dug into a bit further and for some reason a click() is sent when Bootstrap tries and fails hide.bs.dropdown, followed by another call to hide.bs.dropdown. I got around this issue by forcing the closing click() to occur on the button itself, not the entire dropdown menu.

Live Demo in Bootply

JavaScript

$('.keep-open').on({
    "shown.bs.dropdown": function() { $(this).attr('closable', false); },
    //"click":             function() { }, // For some reason a click() is sent when Bootstrap tries and fails hide.bs.dropdown
    "hide.bs.dropdown":  function() { return $(this).attr('closable') == 'true'; }
});

$('.keep-open').children().first().on({
  "click": function() {
    $(this).parent().attr('closable', true );
  }
})

HTML

<h2>Click the dropdown button </h2>
<p>It will stay open unless clicked again to close </p>

<div class="dropdown keep-open">
    <!-- Dropdown Button -->
    <button id="dLabel" role="button" href="#" data-toggle="dropdown" data-target="#" class="btn btn-primary">
        Dropdown <span class="caret"></span>
    </button>
    
    <!-- Dropdown Menu -->
    <ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
    </ul>
</div>
Community
  • 1
  • 1
ThisIsMikeKane
  • 309
  • 2
  • 4
4

$('.dropdown.keep-open').on({
    "shown.bs.dropdown": function() { this.closable = true; },
    "click":             function(e) { 
        var target = $(e.target);
        if(target.hasClass("btn-primary")) 
            this.closable = true;
        else 
           this.closable = false; 
    },
    "hide.bs.dropdown":  function() { return this.closable; }
});
body {
    margin: 10px;
}
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<h2>Click the dropdown button </h2>
<p>It will stay open unless clicked again to close </p>

<div class="dropdown keep-open">
    <!-- Dropdown Button -->
    <button id="dLabel" role="button" href="#"
       data-toggle="dropdown" data-target="#" 
       class="btn btn-primary">
        Dropdown <span class="caret"></span>
    </button>
    
    <!-- Dropdown Menu -->
    <ul class="dropdown-menu" role="menu" 
        aria-labelledby="dLabel">
        <li><a href="#">Action</a></li>
        <li><a href="#">Another action</a></li>
        <li><a href="#">Something else here</a></li>
        <li class="divider"></li>
        <li><a href="#">Separated link</a></li>
    </ul>
</div>




<!-- Post Info -->
<div style='position:fixed;bottom:0;left:0;    
            background:lightgray;width:100%;'>
    About this SO Question: <a href='http://stackoverflow.com/q/19740121/1366033'>Keep dropdown menu open</a><br/>
    Fork This Skeleton Here <a href='http://jsfiddle.net/KyleMit/kcpma/'>Bootrsap 3.0 Skeleton</a><br/>
    Bootstrap Documentation: <a href='http://getbootstrap.com/javascript/#dropdowns'>Dropdowns</a><br/>
<div>
bhavik
  • 41
  • 1
4

I found a solution that requires no new js. Don't use a drop down and use bootstrap collapse instead. I still use some dropdown classes to style it like a dropdown.

<div class="dropdown">
    <button class="dropdown-toggle" type="button" data-toggle="collapse" data-target="#myList">Drop Down
    <span class="caret"></span></button>
    <div id="myList" class="dropdown-menu">
        <input type="checkbox" name="vehicle" value="Bike"> I have a bike<br>
        <input type="checkbox" name="vehicle" value="Car"> I have a car<br></div>
2

I managed to use a combination of KyleMitt's solution above and ran into issues when using this within a Footable object (I believe this is due to the dynamic creation of the table). I applied .keep-open to the .dropdown .div at the top level.

$('#contact_table').on("click", '.keep-open', function () {
    this.closable = false;
});

$('#contact_table').on("shown.bs.dropdown", '.keep-open', function () {
    this.closable = true;
});
$('#contact_table').on("hide.bs.dropdown", '.keep-open', function () {
    let ret = this.closable;
    this.closable = true;
    return ret;
});

The functionality of this code allows you to click outside to close the dropdown, but clicking on items within it would maintain it being open. Please let me know if you have any suggestions/comments on this and I will attempt to edit.

Honga
  • 21
  • 2
1

Mike Kane's solution worked most of the time, but there was a case where the hide.bs.dropdown event was firing before the click() event which caused the dropdown to not close when it should have.

I have come up with with another method that checks the clickEvent object in the event. My original plan was to go up the DOM and check that the clickEvent target was or was not a child of the dropdown, but found that if you click inside the dropdown clickEvent is undefined, and if you click outside of it the event is an object.

So it's just a simple check on whether the clickEvent exists as an object.

$('.dropdown.keep-open').on({
    "hide.bs.dropdown":  function(e) {
        return (typeof(e.clickEvent) != 'object');
    }
});
0

Other solution for this. Keep dropdown open after clicking inside .dropdown-menu:

$('.heading .options .dropdown').on({
    "shown.bs.dropdown":function(){this.closable = true;},
    "click":            function(e){
        var target = $(e.target);
        var d = target.data();
        if(typeof d.toggle != 'undefined' && d.toggle == 'dropdown')
            this.closable = true;
        else {
            var p = target.parent();
            var dd = p.data();
            if(typeof dd.toggle != 'undefined' && dd.toggle == 'dropdown')
                this.closable = true;
            else {
                if(target.hasClass('dropdown-menu'))
                    this.closable = false;
                else {
                    var pp = target.parent('.dropdown-menu');
                    if(typeof pp != 'undefined')
                        this.closable = false;
                    else
                        this.closable = true;
                }
            }
        }
    },
    "hide.bs.dropdown": function(){return this.closable;}
});
Tomasz Majerski
  • 199
  • 2
  • 7
0

Keep dropdown open after clicking inside .dropdown-menu

  $(document.body).on({
    "shown.bs.dropdown": function(){ this.closable = true; },
    "hide.bs.dropdown": function(){ return this.closable; },
    "click": function(e){ this.closable = !$(e.target).closest(".dropdown-menu").length; },
  },".dropdown.keepopen");
0
$('.dropdown.keep-open').on({
    "shown.bs.dropdown": function(){ 
        this.closable = true; 
    },
    "hide.bs.dropdown": function(e){ 
        if(!this.closable){
            this.closable = true;
            return false;
        }
        return this.closable; 
    },
    "click": function(e){ 
        this.closable = false;
    }
});