Twitter Bootstrap: Dropdown on Hover Plugin

Please report any bugs on GitHub, as it's easier to manage than bugs reported in the comments here.

[Update: 31 March 2013] I have a new way of editing posts, so I can import the actual code now for the plugin, making it easier to update, so I'll keep the code on this page.

[Update: 16 March 2013] It's tough to keep the code in this post updated automagically, so I am removing the code from the post. Please visit GitHub for the source code. The download and demo links on these pages link directly to a copy of exactly what's in GitHub, so I'll keep those here for convenience (some people are still intimidated by GitHub).

[Update: 17 Oct 2012] I added some features to the plugin and added the details on this post (as well as the new code). I also put the code on GitHub, scroll down for the link.

There is a lot of discussion about the Twitter Bootstrap dropdowns and the fact that they do not activate on hover. I've read some reasons against hover, and even some from one of the creates of Bootstrap, and they are good points.

Sometimes though, I do like a good hover. So I wrote a plugin that you can use that gives a nice hover with a close-after-delay effect. You can optionally choose to close all other navs as soon as you hover over the next, and you can also set the delay time (500ms by default).

The delay is nice, because it doesn't punish users for moving their mouse 1px outside the dropdown (which would close it without the delay). There is also a small space between the button and the dropdown, where without the delay, it would close if your mouse went over it, so the delay helps with that, too.

This won't affect your mobile users. As a matter of fact, I think it enhanced the experience I had on my iPad a little bit. Without this plugin, once I opened a nav, I couldn't close it, but once I open another nav, it at least closes the last one I opened.

Alright, enough talking... the code:

/*
 * Project: Twitter Bootstrap Hover Dropdown
 * Author: Cameron Spear
 * Contributors: Mattia Larentis
 *
 * Dependencies?: Twitter Bootstrap's Dropdown plugin
 *
 * A simple plugin to enable twitter bootstrap dropdowns to active on hover and provide a nice user experience.
 *
 * No license, do what you want. I'd love credit or a shoutout, though.
 *
 * http://cameronspear.com/blog/twitter-bootstrap-dropdown-on-hover-plugin/
 */
;(function($, window, undefined) {
    // outside the scope of the jQuery plugin to
    // keep track of all dropdowns
    var $allDropdowns = $();

    // if instantlyCloseOthers is true, then it will instantly
    // shut other nav items when a new one is hovered over
    $.fn.dropdownHover = function(options) {

        // the element we really care about
        // is the dropdown-toggle's parent
        $allDropdowns = $allDropdowns.add(this.parent());

        return this.each(function() {
            var $this = $(this).parent(),
                defaults = {
                    delay: 500,
                    instantlyCloseOthers: true
                },
                data = {
                    delay: $(this).data('delay'),
                    instantlyCloseOthers: $(this).data('close-others')
                },
                settings = $.extend(true, {}, defaults, options, data),
                timeout, subTimeout;

            $this.hover(function() {
                if(shouldHover()) {
                    if(settings.instantlyCloseOthers === true)
                        $allDropdowns.removeClass('open');

                    window.clearTimeout(timeout);
                    $(this).addClass('open');
                }
            }, function() {
                if(shouldHover()) {
                    timeout = window.setTimeout(function() {
                        $this.removeClass('open');
                    }, settings.delay);
                }
            });

            $this.find('.dropdown-submenu').hover(function() {
                if(shouldHover()) {
                    window.clearTimeout(subTimeout);
                }
                $(this).children('.dropdown-menu').show();
            }, function() {
                var $submenu = $(this).children('.dropdown-menu');
                if(shouldHover()) {
                    subTimeout = window.setTimeout(function() {
                        $submenu.hide();
                    }, settings.delay);
                } else {
                    // emulate Twitter Bootstrap's default behavior
                    $submenu.hide();
                }
            });
        });
    };

    // helper function to see if we should hover
    var shouldHover = function() { return !!$('#cwspear-is-awesome').height(); };
    $(document).ready(function() {
        // apply dropdownHover to all elements with the data-hover="dropdown" attribute
        $('[data-hover="dropdown"]').dropdownHover();

        // pure win here: we create these spans so we can test if we have the responsive css loaded
        // this is my attempt to hopefully make sure the IDs are unique
        $('').appendTo('body');
    });

    // for the submenu to close on delay, we need to override Bootstrap's CSS in this case
    var css = '.dropdown-submenu:hover>.dropdown-menu{display:none}';
    var style = document.createElement('style');
    style.type = 'text/css';
    if (style.styleSheet) {
        style.styleSheet.cssText = css;
    } else {
        style.appendChild(document.createTextNode(css));
    }
    $('head')[0].appendChild(style);
})(jQuery, this);

The markup must be the same as it normally is with Bootstrap's dropdowns, and then to activate, you just add data-hover="dropdown" where you'd add data-toggle="dropdown". For more options and usage, please go to GitHub

<li class="dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown" data-hover="dropdown" data-delay="1000" data-close-others="false">
        Account <b class="caret"></b>
    </a>
    <ul class="dropdown-menu">
        <li><a tabindex="-1" href="#">My Account</a></li>
        <li class="divider"></li>
        <li><a tabindex="-1" href="#">Change Email</a></li>
        <li><a tabindex="-1" href="#">Change Password</a></li>
        <li class="divider"></li>
        <li><a tabindex="-1" href="#">Logout</a></li>
    </ul>
</li>

Please report any bugs on GitHub, as it's easier to manage than bugs reported in the comments here. Also note that 99% of the issues people are having can be solved by double checking your markup!

Demo: Twitter Bootstrap: Dropdown on Hover
Fork: GitHub
Download: uncompressed | minified

  • http://www.vuzzthemes.com/ Vuzz

    Perfect. Thank you!

  • http://examine.com Sol Orwell

    Fantastic - thanks. Will be using this. Much better than the various JS/CSS hacks you find on StackOverflow

  • RuslanCC

    Very helpful for me, thanks!

  • Erwan

    very very cool - many thanks for putting this up!!

  • http://www.kunstdesign.com.br Gabriel Del Fiaco

    Well done, thank you very much =D

  • http://www.thenextweb.com Pascal Verstegen

    I love you.

  • Ly

    where should i paste the js code? or should i create a new js file for it?

    • http://cameronspear.com CWSpear

      It is intended to be a separate include. Right after you include bootstrap.js, include this file. That way, you can update Bootstrap without having to modify it again.

      Alternatively, and preferably, you have a build step in your process that concatenates and minifies all of your needed scripts into one. Same idea for this method though, the bootstrap.js needs to go before this one.

  • Ly

    I've already figured it out. Thanks.

  • http://gilangaramadan.blogspot.com Gilang

    woooow thank you!

  • http://www.webileapps.com Satya Kalluri

    Works like a charm. Thanks a bunch.

  • http://www.pdvictor.com Peter Drinnan

    This is one less click for man, one giant less click for mankind.

    Thanks man!

  • Pingback: 最全的 Twitter Bootstrap 开发资源清单 – 仓颉的时光记事本

  • Pingback: 最全的 Twitter Bootstrap 开发资源清单 | 乱炖

  • Pingback: twitter-bootstrap-resources | Father Milk

  • Pingback: twitter-bootstrap-resources

  • http://perfectspace.com Brandon Ferens

    This plugin is perfect. You should do the same with popover's.

    • http://cameronspear.com CWSpear

      What do you mean 'popovers'? I don't see anything by that name on Twitter's page.

      It already works with buttons and tabs. See the updated Demo Page

  • Pingback: THE BIG BADASS LIST OF 210 USEFUL TWITTER BOOTSTRAP RESOURCES « Creative Digital Media

  • http://wb.agilecoders.de Michael Haitz

    great plugin, thanks.
    I've added your script to wicket-bootstrap (https://github.com/l0rdn1kk0n/wicket-bootstrap)

  • Eddie

    Great! How about some easing on the dropdown, a little simple jquery animation?

    • http://cameronspear.com CWSpear

      The intention was to keep it simple and integrate with Bootstrap. While possible, not really in the scope of what I intended to do, and I don't think it's all that necessary. People tend to get a little carried away with their animations.

      That being said, anyone is welcome to create a fork on GitHub and implement some animations and options. Shouldn't be terrible difficult.

      • Prof

        This is how a made sliding animation:
        (just few lines of code)


        $this.hover(function() {
        if(options.instantlyCloseOthers === true)
        $allDropdowns.removeClass('open');

        window.clearTimeout(timeout);
        $(this).find('.dropdown-menu').slideDown();
        $(this).addClass('open');
        }, function() {
        timeout = window.setTimeout(function() {
        $this.find('.dropdown-menu').hide();
        $this.removeClass('open');
        }, options.delay);
        });

  • Amila

    Hi,

    This works great, I was using some css to work this out. But it didn't work very well.

    Anyways, Have a question. If you click on the dropdown toggle "a" tag, it will still open the dropdown. but if you hover out of it, there will be a border remaining around the "a" tag. I thought it's something to do with the focus, and used blur just after where you remove the "open" class (2 places in your code). But it didn't work.

    Do you know if there is a way to remove that border?

    • http://cameronspear.com CWSpear

      I'm not quick sure what you mean? I don't see any borders.

      If you have unwanted focus borders around a tags, you can always use a a:focus { outline: 0 none; } in your CSS.

  • Pingback: Free Download » Riddler (Bootstrap)

  • http://stoopidmonkey.net Ian

    Awesome plugin, is there anyway to make it so when you hover over the menu the :hover takes effect, see images below.

    The Register is hovered: http://i.stoopidmonkey.net/mTJaG.jpg

    The drop down is now hovered it only makes the text a tad darker for some reason: http://i.stoopidmonkey.net/Qq8fC.jpg

    And when hovering over the sub items there is no hover effect at all, I tried playing around but couldn't get it to work: http://i.stoopidmonkey.net/EaHJJ.jpg

    Thanks again,

    • http://cameronspear.com CWSpear

      I'm not 100% sure what you're asking and your 2nd image is something from Facebook, I think...

      But I didn't add any CSS to the plugin, so that's something done in Bootstrap.

      • Ian

        Wow totally failed there.

        I'll play around with the CSS see if i can get it to work, anyhow thanks alot :)

  • http://sanglier.co.uk Joss

    I am having one little problem - on your demo, when you open the menu (in a small view port) all your menu items are already expanded.

    However, mine aren't, which is really frustrating!

    Did you do anything special in your menu markup or in the CSS that makes the menu fully expanded automatically?

    Otherwise - great little utility! Thanks

    • http://cameronspear.com CWSpear

      I copied the markup from the Bootstrap demos exactly. Markup is very important.

      I didn't add any CSS related to the menus, so it's likely your markup is wrong or something along those lines.

  • http://sanglier.co.uk Joss

    HI CW

    The markup is completely normal - it is dynamically generated, but it is the markup I normally use.

    I checked with the Bootstrap site, looking at the demo for the responsive menu. That does not have the child items automatically expanded either. So, I am not sure what is different about yours!

    With the hover, it is certainly useful to have them expanded out when it comes to touch devices.

    • http://sanglier.co.uk Joss

      One other thought - on your demo you are using BS 2.1.1, rather than 2.2.2

      Could that be it?

      • http://cameronspear.com CWSpear

        That's the only thing I could think of. I have no idea what else could be different!

  • http://brockis.com Jesse

    I found I needed to add this to my override css (in my case app.css) to force the menu to expand all sub menu items on tablet/mobile. You could also edit this property in bootstrap media queries.

    @media (max-width: 979px) {
    .nav-collapse .dropdown-menu {display: block;}
    }

  • Jonny

    Hi Cameron, This is great! How would I go about restoring a menu item's click functionality? ie. when you hover the menu item you see the drop down menu, but if you click the menu item it takes you to its href='' location. Many thanks

  • http://www.ddesigners.nl/braam/index.html Sito

    Hi! a good plugin! but help(!) my problem is that my submenu-items do not keep 'expanded' ..they collapse each time , and shut down..so the user has to start all over again at the menu to get to see the rest of the submenu-list-items!

    Hope you can help me out please!

  • http://www.ddesigners.nl/braam/index.html Sito

    I found I needed to add this to my override css (in my case app.css) to force the menu to expand all sub menu items on tablet/mobile.

    I treid this, cause I think this is what I need, but it does not work :-(

  • http://www.ddesigners.nl/braam/index.html Sito

    Display block causes the whole menu to expand, it works, but not like a charm....I have 6 submenu-list-items....

    I like to just expand the submenu-items on hover, or on click, and stay expanded when navigating to another page....

    Is something like that possible?

  • http://www.ddesigners.nl/braam/index.html Sito

    The issue is just for IPhone and IPad.....

  • http://www.valdeirsantana.com.br Valdeir

    Thanks!! Very Good!

  • Pingback: (转)最全的 Twitter Bootstrap 开发资源清单 - 小小站

  • http://www.tribeleadr.com/ Harold

    Hi ! That's really handy ! Thank you ! ^^

  • http://conquatheme.com Marcin

    Thanks a lot

    I Joomla 2.5.8 some dropdowns doesn't work properly. Your soultion helped me to solve this problem

    Marcin

  • Oleg

    Semi greate, it didn't work with submenu.
    if i move mouse thru the free space, the links block closes instantly.

  • gigi

    how to insert a space "offset"? the anchors end up under a fixed header.
    thanks ;)

  • cynthusia

    Awesome stuff here. I am working within the WordPress Bootstrap theme so, I don't have full control of the html, as it's coming from

    and is communicating with functions.php. As a novice coder, I tried editing functions.php to include, for example, data-hover="dropdown" data-delay="1000" data-close-others="false"

    But it didn't change anything. Though when I paste in your raw html for the "nav-collapse" div and contents (from the demo page), it works - but only the sub items work; the parent nav is still not functioning on hover.

    Anyway, assuming I can eventually get this to work, does your code also allow for the Parent link to hyperlink to a page? In the demo they are not set up to, so I can't tell if it would work or not.

    Thank you! You are saving lives :)

  • cynthusia

    That didn't go as planned. I had some php tags within the code tag, and it didn't like it. I was trying to say

    php bones_main_nav(); // Adjust using Menus in WordPress Admin

    Hopefully that worked :\ If not, feel free to email me. Thanks!

  • http://www.tribeleadr.com/ Harold

    Hi ! Nice one ! This really helped me for my WordPress Bootstraped theme ! Want to check it out ? It's right here : https://github.com/haroldparis/origines

  • http://www.twitter.com/LFeh Felipe

    Friend, your solution is sensational. But there's a problem when you add submenu within another. It removes all classes "open" and close everything was open. I have little knowledge of javascript, and unfortunately I can not solve this problem.

    Can you help?

  • Pingback: BootStrap资源列表 | Tengfei's Blog

  • Pingback: GitHub托管BootStrap资源汇总…(不断更新中) | 梧桐树下

  • http://inprocess TJ Sherrill

    your hover delay doesn't appear to be working on the demo page. I was exited to find this and reading the comments people seem to be liking the plugin but the delay was what I really needed.

  • http://www.truespire.com Wesley

    Nice plugin, works great except I found a bug...

    JS Hint threw this warning:
    'options' is defined but never used.
    on Line 21: $.fn.dropdownHover = function(options)

    When I implemented the plugin via javascript everything worked except the custom options I passed in were ignored. When I use data-delay="1000" I am able to change the delay option just fine.

    Other than that, this plugin has been a big help.

    Thanks!

  • Anthony

    Just a reply to Felipe, I had the same issue so I changed the following:
    $.fn.dropdownHover = function(options) to
    $.fn.dropdownHover = function(myOptions)

    and

    options = $.extend(true, {}, defaults, options, data) to
    options = $.extend(true, {}, defaults, myOptions, data),

    Works a treat now even with submenu of a submenu.

    • http://cameronspear.com CWSpear

      Yeah, sorry. Because I declared var options it trumped scope and so when I used it in the $.extend it was undefined.

      I fixed it though. Thank you (and the others that pointed out the issue and offered solutions) for the help!

  • Anthony

    Sorry I should add I had to do this due to my options not being picked up by the function and I knew to keep the parent from closing when viewing a submenu I had to have this option:

    $('.dropdown-toggle').dropdownHover({
    instantlyCloseOthers: false
    });

    But my option was not being picked up by the function there was a conflict of name space. I know I could have just changed this within the function itself but I knew what the problem was so I fixed it.

  • Larry

    I hate using a bunch of plugins in a website, but I decided to give this a try because I couldn't get any other hacks to work. Dropped it in and it works perfectly. A+ work!

  • http://eworks.co.zw Duma Mtungwa

    Thanks Cameron, works like a charm, you saved me hours of heartache.

  • Pingback: Complete List of Bootstrap Resources | America's Web Developers – WebMedia FX

  • http://twitter.com/JohnMarkDonegan Mark Donegan

    Am i missing the bleedin' obvious? I've added a li item which does not have a submenu but this isn't using the hover style of all the parent li items and the hover delay isn't cancelling when the menu item (with no submenu) is hovered??

    • http://twitter.com/JohnMarkDonegan Mark Donegan

      NUMPTY ALERT!! Yep that was me!
      Had my markup a little bit screwy.

      Brill plugin btw.

  • http://salacioussound.com/ Cal

    Took me less than five minutes to implement. Thanks a lot for writing this!

    One other thing I want to do now is re-enable the default behaviour on a dropdown top level item, making the parent clickable

  • Avelino Tiu

    im not sure if this can be done with your plugin:

    can we do hover on regular desktops? and click on mobile devices? im using the responsive navbar for my responsive website..

    thanks

  • http://www.facebook.com/joachim.otto.77 Joachim Otto

    Thanks a lot for writing the script.

    It is easy to contain it.

    Thanks !!!

  • Tom

    Cameron, thanks so much for this plugin. It´s such a tremendous help and implemented virtually within seconds.

  • dhika

    this is what i'm looking for, fabolous.. thanks dude

  • http://twitter.com/NielsAlbjerg Niels A. Kristiansen

    Is it also possible to get it to work with a split button? The hover works when the mouse is going into the button/link from top, bottom and right. But if the mouse cursor parsing from the left (over the first button/link) then the dropdown never appears. Is there an easy fix for that?

Loading...