falter
falter

Reputation: 13644

How to make Twitter Bootstrap menu dropdown on hover rather than click

I'd like to have my Bootstrap menu automatically drop down on hover, rather than having to click the menu title. I'd also like to lose the little arrows next to the menu titles.

Upvotes: 1251

Views: 852512

Answers (30)

Radmation
Radmation

Reputation: 1534

Bootstrap versions 4 and 5 solutions. (IE compatible)

These are complete solutions that use the mouseover and mouseleave events and some screen width checking. This is better than a pure CSS solution.

Bootstrap v5 - Pure JS (intended for webpack)

export class BootstrapOpenMenuHover {

/**
 * Constructor.
 */
constructor() {
  this.windowWidth = window.innerWidth;
  this.mobileBreakPoint = 991; // Put your menu break point here, when it switches to a hamburger icon.
  this.dropdownNavItems = document.querySelectorAll(".dropdown-toggle.nav-link");
  this.dropdownMenuItems = document.querySelectorAll(".dropdown-menu");

  this.setEventListeners();
}

/**
 * Set all of our event listeners.
 */
setEventListeners() {
  const _self = this;

  // To be safe set the width once the dom is loaded.
  window.addEventListener('load',  function () {
    _self.windowWidth = window.innerWidth;
  });

  // Keep track of the width in the event of a resize.
  window.addEventListener('resize',  function () {
    _self.windowWidth = window.innerWidth;
  });

  // Bind our hover events.
  if (_self.dropdownNavItems !== null)  {
    for (let i = 0; i < _self.dropdownNavItems.length; i++) {

      // On mouse enter.
      _self.dropdownNavItems[i].addEventListener('mouseenter', function () {
        if (_self.windowWidth >= _self.mobileBreakPoint) {
          this.classList.add('show');
          this.ariaExpanded = true;
          this.dataset.bsToggle = null;

          // Update the .dropdown-menu
          this.nextElementSibling.classList.add('show');
          this.nextElementSibling.dataset.bsPopper = 'none';
        }
      });

      // On mouse leave.
      _self.dropdownNavItems[i].addEventListener('mouseleave', function () {
        if (_self.windowWidth >= _self.mobileBreakPoint) {
          this.classList.remove('show');
          this.ariaExpanded = false;
          this.dataset.bsToggle = 'dropdown';

          // Update the .dropdown-menu
          this.nextElementSibling.classList.remove('show');
          this.nextElementSibling.dataset.bsPopper = null;
        }
      });
    }
  }

  // Bind events to .dropdown-menu items.
  if (_self.dropdownMenuItems !== null) {
    for (let i = 0; i < _self.dropdownMenuItems.length; i++) {
      // On mouse enter.
      _self.dropdownMenuItems[i].addEventListener('mouseenter', function () {
        if (_self.windowWidth >= _self.mobileBreakPoint) {
          this.classList.add('show');
          this.dataset.bsPopper = 'none';

          // Update the .dropdown-toggle
          this.previousElementSibling.classList.add('show');
          this.previousElementSibling.ariaExpanded = true;
          this.previousElementSibling.dataset.bsToggle = null;
        }
      });

      // On mouse leave.
      _self.dropdownMenuItems[i].addEventListener('mouseleave', function () {
        if (_self.windowWidth >= _self.mobileBreakPoint) {
          this.classList.remove('show');
          this.dataset.bsPopper = null;

          // Update the .dropdown-toggle
          this.previousElementSibling.classList.remove('show');
          this.previousElementSibling.ariaExpanded = false;
          this.previousElementSibling.dataset.bsToggle = 'dropdown';
        }
      });
    }
   }
  }
 }

 const bootstrapOpenMenuHover = new BootstrapOpenMenuHover();

Bootstrap v4 Solution

This will allow you to follow top level navigation links.

This was built with desktop and mobile in mind. Fell free to change the BREAK_POINT variable to suit your needs :D.

jQuery

var WINDOW_WIDTH;
var BREAK_POINT = 991;

(function ($) {

    /** Set window width onload */
    WINDOW_WIDTH = $(window).width(); // Returns width of browser viewport
    /** Set window width if the browser is resized */
    $(window).resize(function () {
        WINDOW_WIDTH = $(window).width(); // Returns width of browser viewport
    });

    /** Dropdown menu on mouseenter */
    $(".nav-item.dropdown").on('mouseenter', function () {
        console.log("mouseenter");
        if (WINDOW_WIDTH >= BREAK_POINT) {
            // Open up the dropdown
            $(this).addClass('show'); // add the class show to the li parent
            $(this).children('.nav-link').removeAttr('data-toggle'); // remove the data-toggle attribute so we can click and follow link
            $(this).children('.dropdown-menu').addClass('show'); // add the class show to the dropdown div sibling
        }
    });
    /** Dropdown menu on mouseleave */
    $(".nav-item.dropdown").on('mouseleave', function () {
        console.log("mouseleave");
        if (WINDOW_WIDTH >= BREAK_POINT) {
            // Close the dropdown
            $(this).removeClass('show'); // add the class show to the li parent
            $(this).children('.nav-link').attr('data-toggle', 'dropdown'); // remove the data-toggle attribute so we can click and follow link
            $(this).children('.dropdown-menu').removeClass('show'); // add the class show to the dropdown div sibling
        }
    });
});

CSS

@media(min-width:  768px) {
  .dropdown-menu {
    margin-top: 0; // fixes closing on slow mouse transition
  }
}

Upvotes: 4

AbdulAhmad Matin
AbdulAhmad Matin

Reputation: 1146

This also can do that.


$('.dropdown').on('mouseover',function(){
    $(this).find('.dropdown-menu').show();
});
$('.dropdown').on('mouseleave',function(){
    $(this).find('.dropdown-menu').hide();
});

If the dropdown has a gap between the hovered element the drop down will immediately close as seen in this GIF

Dropdown hiding as soon as the element is cleared

To prevent this behaviour you can add a timeout to the events of 100 ms

let dropdownTimer;
$('.dropdown').on('mouseover', () => {
    clearTimeout(dropdownTimer)
    $(this).find('.dropdown-menu').show();
});
$('.dropdown').on('mouseleave', () =>{
    dropdownTimer = setTimeout(() => {
        $(this).find('.dropdown-menu').hide();
    }, 100)
});

Dropdown holding open for a set timeout

Upvotes: 7

Max Filippov
Max Filippov

Reputation: 2082

Just want to add, that if you have multiple dropdowns (as I do) you should write:

ul.nav li.dropdown:hover > ul.dropdown-menu {
    display: block;    
}

And it'll work properly.

Upvotes: 11

Amay Kulkarni
Amay Kulkarni

Reputation: 838

This worked for me:

.dropdown:hover .dropdown-menu {
    display: block;
}

Upvotes: 21

BSUK
BSUK

Reputation: 745

This is built into Bootstrap 3. Just add this to your CSS:

.dropdown:hover .dropdown-menu {
    display: block;
}

Upvotes: 16

Ranjith
Ranjith

Reputation: 2819

Simply customize your CSS style in three lines of code

.dropdown:hover .dropdown-menu {
   display: block;
}

Upvotes: 78

Cory Price
Cory Price

Reputation: 2458

In addition to the answer from "My Head Hurts" (which was great):

ul.nav li.dropdown:hover ul.dropdown-menu{
    display: block;    
}

There are 2 lingering issues:

  1. Clicking on the dropdown link will open the dropdown-menu. And it will stay open unless the user clicks somewhere else, or hovers back over it, creating an awkward UI.
  2. There is a 1px margin between the dropdown link, and dropdown-menu. This causes the dropdown-menu to become hidden if you move slowly between the dropdown and dropdown-menu.

The solution to (1) is removing the "class" and "data-toggle" elements from the nav link

<a href="#">
     Dropdown
     <b class="caret"></b>
</a>

This also gives you the ability to create a link to your parent page - which wasn't possible with the default implementation. You can just replace the "#" with whatever page you want to send the user.

The solution to (2) is removing the margin-top on the .dropdown-menu selector

.navbar .dropdown-menu {
    margin-top: 0px;
}

Upvotes: 236

Farhad Sakhaei
Farhad Sakhaei

Reputation: 922

The most Standard Answer:

  • Supports aria-expanded attribute
  • Supports non touch devices
  • Supports touch devices
  • Supports all dropdowns
var isTouchDevice = (('ontouchstart' in window) ||
                                (navigator.MaxTouchPoints > 0) ||
                                (navigator.msMaxTouchPoints > 0));
if(!isTouchDevice){
    // open dropdowns on hover on non mobile devices
    $(".dropdown").hover(function(e) {
        $('.dropdown-toggle', this).dropdown("toggle");
        e.stopPropagation();
    });
    // prevent blinkling
    $(".submenu-link").click(function(e) {
        e.stopPropagation();
    });
}

You can change $(".dropdown") to a specific area if you need:

$("#top-menu .dropdown")

Upvotes: 3

Julesezaar
Julesezaar

Reputation: 3406

Bootstrap 4, 2019

I read a lot of these answers but I ended up doing it myself because it was just not what i needed.

I have Bootstrap 4, and want to keep the click + the hover functionality. Besides I want to enable it only on dropdowns that have an extra class ".open-on-hover".

I also want to keep the Bootstrap's Jquery that positions the dropdown when it is next to the edge of the page. So we don't just want to do "display: block". We want the full Bootstrap's way of working. So I just trigger click.

The logic is "If it is a mouseenter then open it, if it is a mouseleave then hide it if it is open"

/**
 * Open Bootstrap 4 dropdown on hover
 */
$(document).on('mouseenter mouseleave', '.dropdown.open-on-hover', function(e) 
{
    let toggler = $(this).find('[data-toggle="dropdown"]').first();

    if(e.type === 'mouseenter') {
        $(toggler).trigger('click', 'open');
    } else if ($(this).children('.dropdown-menu.show').length) {
        $(toggler).trigger('click', 'close');
    }
});

The html

<div class="dropdown open-on-hover">
    <div class="btn" data-toggle="dropdown">
        Hover or click me
    </div>
    <div class="dropdown-menu">
        <a class="dropdown-item">
            Item 1
        </a>
        <a class="dropdown-item">
            Item 2
        </a>
    </div>
</div>

Upvotes: 2

Drew
Drew

Reputation: 4373

This works for Bootstrap V4

JS:

<script>
        $(function() {
            $('.dropdown-hover').hover(
                function() { $(this).addClass('show'); $(this).find('[data-toggle="dropdown"]').attr('aria-expanded', true); $(this).find('.dropdown-menu').addClass('show'); },
                function() { $(this).removeClass('show'); $(this).find('[data-toggle="dropdown"]').attr('aria-expanded',false); $(this).find('.dropdown-menu').removeClass('show'); }
            );
        });
    </script>

Vanilla Bootstrap 4 Dropdown HTML except for the addition of the dropdown-hover class:

<div class="dropdown dropdown-hover">
<button class="btn btn-text dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    ABOUT
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
    <a class="dropdown-item" href="#">Action</a>
    <a class="dropdown-item" href="#">Another action</a>
    <a class="dropdown-item" href="#">Something else here</a>
</div>

If you don't want to selectively enable the hover feature by using the .dropdown-hover class then simply change the jquery selector from .dropdown-hover to .dropdown.

Upvotes: 5

Kash
Kash

Reputation: 1801

The very simple solution for version 2, only CSS. Keeps the same friendly functionality for mobile and tablet.

@media (min-width: 980px) {
    .dropdown:hover .dropdown-menu {
       display: block;
    }
}

Upvotes: 4

maestar
maestar

Reputation: 59

Adding this for those who want default functionality on mobile devices. Can set min-width: ... as required

@media only screen and (min-width: 1195px) {
  ul.nav li.dropdown:hover > ul.dropdown-menu {
    display: block;
  }
  ul.nav li.dropdown> ul.dropdown-menu {
    display: none;
  }
}

setting display: none so that dropdown-toggle won't create an issue. If you leave it as is, there might be two dropdowns open at the same time.

Upvotes: 1

I have published a proper plugin for the Bootstrap 3 dropdown hover functionality, in which you can even define what happens when clicking on the dropdown-toggle element (the click can be disabled):

https://github.com/istvan-ujjmeszaros/bootstrap-dropdown-hover


Why I made it when there are many solutions already?

I had issues with all the previously existing solutions. The simple CSS ones are not using the .open class on the .dropdown, so there will be no feedback on the drop-down toggle element when the drop-down is visible.

The js ones are interfering with clicking on .dropdown-toggle, so the dropdown shows up on hover, then hides it when clicking on an opened drop-down, and moving out the mouse will trigger the drop-down to show up again. Some of the js solutions are breaking iOS compatibility, some plugins are not working on modern desktop browsers which are supporting the touch events.

That's why I made the Bootstrap Dropdown Hover plugin which prevents all these issues by using only the standard Bootstrap javascript API, without any hack. Even the Aria attributes are working fine with this plugin.

Upvotes: 6

Ankur Sahu
Ankur Sahu

Reputation: 134

I hope this helps. Check the link https://jsfiddle.net/awb7gfb1/

<nav>
    <div id="menubar" class=" collapse navbar-collapse row">
        <ul id="dropdownNavbar" class="nav navbar-nav">
            <li class="dropdown">
                <button type="button" class="btn btn-primary dropbtn"><span class="glyphicon glyphicon-time"></span>
                Time Card
                <span class="caret"></span></button>
                <div class="dropdown-content">
                    <a id="showTimeCard" href="#">My Time Card</a>
                    <a href="#">Sub Menu 2</a>
                    <a href="#">Sub Menu 3</a>
                    <a href="#">Sub Menu 4</a>
                    <a href="#">Sub Menu 5</a>
                </div>
            </li>
            <li class="dropdown">
                <button type="button" class="btn btn-primary dropbtn"><span class="glyphicon glyphicon-stats"></span>
                Project
                <span class="caret"></span></button>
                <div class="dropdown-content">
                    <a href="#">Sub Menu 1</a>
                    <a href="#">Sub Menu 2</a>
                    <a href="#">Sub Menu 3</a>
                </div>
            </li>
            <li class="dropdown">
                <button type="button" class="btn btn-primary dropbtn"><span class="glyphicon glyphicon-user"></span>
                HR Links
                <span class="caret"></span></button>
                <div class="dropdown-content">
                    <a href="#">Sub Menu 1</a>
                    <a href="#">Sub Menu 2</a>
                </div>
            </li>
            <li class="dropdown">
                <button type="button" class="btn btn-primary dropbtn">
                <span class="glyphicon glyphicon-screenshot"></span>
                Leave Tracker
                <span class="caret"></span></button>
                <div class="dropdown-content">
                    <a href="#">Sub Menu 1</a>
                    <a href="#">Sub Menu 2</a>
                    <a href="#">Sub Menu 3</a>
                    <a href="#">Sub Menu 4</a>
                </div>
            </li>
            <li class="dropdown">
                <button type="button" class="btn btn-primary dropbtn">
                <span class="glyphicon glyphicon-briefcase"></span>
                Accounts
                <span class="caret"></span></button>
                <div class="dropdown-content">
                    <a href="#">Sub Menu 1</a>
                    <a href="#">Sub Menu 2</a>
                    <a href="#">Sub Menu 3</a>
                    <a href="#">Sub Menu 4</a>
                    <a href="#">Sub Menu 5</a>
                </div>
            </li>
            <li class="dropdown">
                <button type="button" class="btn btn-primary dropbtn">
                <span class="glyphicon glyphicon-headphones"></span>
                Service Desk
                <span class="caret"></span></button>
                <div class="dropdown-content">
                    <a href="#">Sub Menu 1</a>
                    <a href="#">Sub Menu 2</a>
                    <a href="#">Sub Menu 3</a>
                    <a href="#">Sub Menu 4</a>
                </div>
            </li>
            <li class="dropdown">
                <button type="button" class="btn btn-primary dropbtn">
                <span class="glyphicon glyphicon-file"></span>
                Reports
                <span class="caret"></span></button>
                <div class="dropdown-content">
                    <a href="#">Sub Menu 1</a>
                    <a href="#">Sub Menu 2</a>
                    <a href="#">Sub Menu 3</a>
                    <a href="#">Sub Menu 4</a>
                    <a href="#">Sub Menu 5</a>
                </div>
            </li>
            <li class="dropdown">
                <button type="button" class="btn btn-primary dropbtn">
                <span class="glyphicon glyphicon-cog"></span>
                Settings
                <span class="caret"></span></button>
                <div class="dropdown-content">
                    <a href="#">Sub Menu 1</a>
                    <a href="#">Sub Menu 2</a>
                    <a href="#">Sub Menu 3</a>
                </div>
            </li>
        </ul>
    </div>
</nav>

And the CSS

.dropdown {
    float: left;
    padding-right: 1px;
}

.dropbtn{
    border: 0px;
    height: 30px;
    border-radius: 0px 10px;
}
li button, .dropbtn {
    display: inline-block;
    color: white;
    text-align: center;
}

li button:hover, .dropdown:hover .dropbtn {
    background-color: #12A5F4;
}

.dropbtn.active {
    background: #12A5F4;
}

.dropdown-content {
    display: none;
    position: absolute;
    background-color: #e8f3f4;
    min-width: 100%;
    box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.1);
    z-index: 10;
}

.navbar-header{
    overflow: visible;
    z-index: 1;
}

.dropdown-content a {
    color: black;
    padding: 5px 10px;
    display: block;
    text-align: left;
}

.dropdown-content a:hover {
    background-color: #d8dee2
}

.dropdown:hover .dropdown-content {
    display: block;
}

#menubar{
    padding-top: 5px;
    overflow: visible;
    z-index: 10;
    padding-left: 0px;
    padding-right: 0px;
    margin: 0px;
}

#dropdownNavbar{
    margin: 0px;
}

.navbar-toggle{
    background-color: #3382d5;
}
.navbar-toggle span{
    background-color: white;
}

Upvotes: 1

Erik Thiart
Erik Thiart

Reputation: 391

Here is the JSFiddle -> https://jsfiddle.net/PRkonsult/mn31qf0p/1/

The JavaScript bit at the bottom is what does the actual magic.

HTML

<!--http://getbootstrap.com/components/#navbar-->
<div class="body-wrap">
  <div class="container">
    <nav class="navbar navbar-inverse" role="navigation">
      <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
          <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Brand</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Link</a></li>
            <li><a href="#">Link</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
              <ul class="dropdown-menu">
                <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>
                <li class="divider"></li>
                <li><a href="#">One more separated link</a></li>
              </ul>
            </li>
          </ul>

          <ul class="nav navbar-nav navbar-right">
            <li><a href="#">Link</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
              <ul class="dropdown-menu">
                <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>
            </li>
          </ul>
        </div>
        <!-- /.navbar-collapse -->
      </div>
      <!-- /.container-fluid -->
    </nav>
  </div>
</div>

CSS

/* Bootstrap dropdown hover menu */

body {
  font-family: 'PT Sans', sans-serif;
  font-size: 13px;
  font-weight: 400;
  color: #4f5d6e;
  position: relative;
  background: rgb(26, 49, 95);
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(26, 49, 95, 1)), color-stop(10%, rgba(26, 49, 95, 1)), color-stop(24%, rgba(29, 108, 141, 1)), color-stop(37%, rgba(41, 136, 151, 1)), color-stop(77%, rgba(39, 45, 100, 1)), color-stop(90%, rgba(26, 49, 95, 1)), color-stop(100%, rgba(26, 49, 95, 1)));
  filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#1a315f', endColorstr='#1a315f', GradientType=0);
}

.body-wrap {
  min-height: 700px;
}

.body-wrap {
  position: relative;
  z-index: 0;
}

.body-wrap: before,
.body-wrap: after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: -1;
  height: 260px;
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, rgba(26, 49, 95, 1)), color-stop(100%, rgba(26, 49, 95, 0)));
  background: linear-gradient(to bottom, rgba(26, 49, 95, 1) 0%, rgba(26, 49, 95, 0) 100%);
  filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#1a315f', endColorstr='#001a315f', GradientType=0);
}

.body-wrap:after {
  top: auto;
  bottom: 0;
  background: linear-gradient(to bottom, rgba(26, 49, 95, 0) 0%, rgba(26, 49, 95, 1) 100%);
  filter: progid: DXImageTransform.Microsoft.gradient(startColorstr='#001a315f', endColorstr='#1a315f', GradientType=0);
}

nav {
  margin-top: 60px;
  box-shadow: 5px 4px 5px #000;
}

Then the important bit of JavaScript code:

$('ul.nav li.dropdown').hover(function() {
  $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn(500);
}, function() {
  $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut(500);
});

Upvotes: 3

F.O.O
F.O.O

Reputation: 4960

Use two links inline. Hide the link with the dropdown toggle and add the onmouseover event over the visible link to click the dropdown menu.

<a class="pretty-button"
   href="#" alt="Notifications"
   onmouseover="$('#notifications-dropdown').click()">
</a>

<a style="display:none"
   id="notifications-dropdown"
   class="js-nav js-tooltip js-dynamic-tooltip"
   href="#"
   alt="Notifications"
   data-toggle="dropdown">
   <span class="fa fa-flag fa-2x"></span>
</a>

Upvotes: 1

Restartit Fbapp
Restartit Fbapp

Reputation: 81

For the caret... I haven't seen any one specifying simple CSS that totally blocks the caret.

Here you go:

.caret {
    display: none !important;
}

Upvotes: 3

Amr
Amr

Reputation: 5159

If you have an element with a dropdown class like this (for example):

<ul class="list-unstyled list-inline">
    <li class="dropdown">
        <a data-toggle="dropdown" href="#"><i class="fa fa-bars"></i> Dropdown 1</a>
        <ul class="dropdown-menu">
            <li><a href="">Item 1</a></li>
            <li><a href="">Item 2</a></li>
            <li><a href="">Item 3</a></li>
            <li><a href="">Item 4</a></li>
            <li><a href="">Item 5</a></li>
        </ul>
    </li>
    <li class="dropdown">
        <a data-toggle="dropdown" href="#"><i class="fa fa-user"></i> Dropdown 2</a>
        <ul class="dropdown-menu">
            <li><a href="">Item A</a></li>
            <li><a href="">Item B</a></li>
            <li><a href="">Item C</a></li>
            <li><a href="">Item D</a></li>
            <li><a href="">Item E</a></li>
        </ul>
    </li>
</ul>

Then you can have the dropdown menu to be automatically drop down on hover over, rather than having to click its title, by using this snippet of jQuery code:

<script>
    $('.dropdown').hover(
        function() {
            $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn();
        },
        function() {
            $(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut();
        }
    );

    $('.dropdown-menu').hover(
        function() {
            $(this).stop(true, true);
        },
        function() {
            $(this).stop(true, true).delay(200).fadeOut();
        }
    );
</script>

Here is a demo

This answer relied on @Michael answer, I have made some changes and added some additions to get the dropdown menu work properly

Upvotes: 25

Sobin Augustine
Sobin Augustine

Reputation: 3775

We saw, In addition to the answer from "My Head Hurts", "Cory Price" found out two problems:

Problem 1: Clicking on the dropdown link will open the dropdown-menu. And it will stay open unless the user clicks somewhere else, or hovers back over it, creating an awkward UI.

Solution: Remove the "class" and "data-toggle" elements from the nav link

The solution was nearly perfect, but the problem here is, when it comes to mobile devices and tablets, it won't work!

I'm using a bit of jQuery code to fix this..

if ($(window).width() > 769) {
    $('.dropdown-toggle').removeAttr('data-toggle');
    $('.dropdown-menu').removeAttr('style');
    $('.dropdown').removeClass('open');
}
$(window).resize(function () {
    if ($(window).width() > 769) {
        $('.dropdown-toggle').removeAttr('data-toggle');
        $('.dropdown-menu').removeAttr('style');
        $('.dropdown').removeClass('open');
    }
    else {
        $('.dropdown-toggle').attr("data-toggle", "dropdown");
    }
});

Note: Here we assume that the collapse to mobile devices and tablets is from 768px.

Upvotes: 1

Crisan Raluca Teodora
Crisan Raluca Teodora

Reputation: 1293

So you have this code:

<a class="dropdown-toggle" data-toggle="dropdown">Show menu</a>

<ul class="dropdown-menu" role="menu">
    <li>Link 1</li>
    <li>Link 2</li> 
    <li>Link 3</li>                                             
</ul>

Normally it works on a click event, and you want it work on a hover event. This is very simple, just use this JavaScript/jQuery code:

$(document).ready(function () {
    $('.dropdown-toggle').mouseover(function() {
        $('.dropdown-menu').show();
    })

    $('.dropdown-toggle').mouseout(function() {
        t = setTimeout(function() {
            $('.dropdown-menu').hide();
        }, 100);

        $('.dropdown-menu').on('mouseenter', function() {
            $('.dropdown-menu').show();
            clearTimeout(t);
        }).on('mouseleave', function() {
            $('.dropdown-menu').hide();
        })
    })
})

This works very well and here is the explanation: we have a button, and a menu. When we hover the button we display the menu, and when we mouseout of the button we hide the menu after 100 ms. If you wonder why I use that, is because you need time to drag the cursor from the button over the menu. When you are on the menu, the time is reset and you can stay there as many time as you want. When you exit the menu, we will hide the menu instantly without any timeout.

I've used this code in many projects, if you encounter any problem using it, feel free to ask me questions.

Upvotes: 3

Mark Williams
Mark Williams

Reputation: 1129

The best way of doing it is to just trigger Bootstrap's click event with a hover. This way, it should still remain touch device friendly.

$('.dropdown').hover(function(){ 
  $('.dropdown-toggle', this).trigger('click'); 
});

Upvotes: 9

Mehdi Maghrouni
Mehdi Maghrouni

Reputation: 1539

I've managed it as follows:

$('ul.nav li.dropdown').hover(function(){
       $(this).children('ul.dropdown-menu').slideDown(); 
    }, function(){
       $(this).children('ul.dropdown-menu').slideUp(); 
});

I hope this helps someone...

Upvotes: 8

Alex
Alex

Reputation: 461

In my opinion the best way is like this:

;(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 = $this.parent(),
                defaults = {
                    delay: 500,
                    instantlyCloseOthers: true
                },
                data = {
                    delay: $(this).data('delay'),
                    instantlyCloseOthers: $(this).data('close-others')
                },
                settings = $.extend(true, {}, defaults, options, data),
                timeout;

            $parent.hover(function(event) {

                // So a neighbor can't open the dropdown
                if(!$parent.hasClass('open') && !$this.is(event.target)) {
                    return true;
                }

                if(settings.instantlyCloseOthers === true)
                    $allDropdowns.removeClass('open');

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

            // This helps with button groups!
            $this.hover(function() {
                if(settings.instantlyCloseOthers === true)
                    $allDropdowns.removeClass('open');

                window.clearTimeout(timeout);
                $parent.addClass('open');
            });

            // Handle submenus
            $parent.find('.dropdown-submenu').each(function(){
                var $this = $(this);
                var subTimeout;
                $this.hover(function() {
                    window.clearTimeout(subTimeout);
                    $this.children('.dropdown-menu').show();

                    // Always close submenu siblings instantly
                    $this.siblings().children('.dropdown-menu').hide();
                }, function() {
                    var $submenu = $this.children('.dropdown-menu');
                    subTimeout = window.setTimeout(function() {
                        $submenu.hide();
                    }, settings.delay);
                });
            });
        });
    };

    $(document).ready(function() {
        // apply dropdownHover to all elements with the data-hover="dropdown" attribute
        $('[data-hover="dropdown"]').dropdownHover();
    });
})(jQuery, this);

Sample markup:

<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>

Upvotes: 8

Fred K
Fred K

Reputation: 13910

This works for WordPress Bootstrap:

.navbar .nav > li > .dropdown-menu:after,
.navbar .nav > li > .dropdown-menu:before {
    content: none;
}

Upvotes: 2

Fizex
Fizex

Reputation: 61

The jQuery solution is good, but it will need to either deal with on click events (for mobile or tablet) as hover won't work properly... Could maybe do some window re-size detection?

Andres Ilich's answer seems to work well, but it should be wrapped in a media query:

@media (min-width: 980px) {

    .dropdown-menu .sub-menu {
        left: 100%;
        position: absolute;
        top: 0;
        visibility: hidden;
        margin-top: -1px;
    }

    .dropdown-menu li:hover .sub-menu {
        visibility: visible;
    }

    .dropdown:hover .dropdown-menu {
        display: block;
    }

    .nav-tabs .dropdown-menu, .nav-pills .dropdown-menu, .navbar .dropdown-menu {
        margin-top: 0;
    }

    .navbar .sub-menu:before {
        border-bottom: 7px solid transparent;
        border-left: none;
        border-right: 7px solid rgba(0, 0, 0, 0.2);
        border-top: 7px solid transparent;
        left: -7px;
        top: 10px;
    }
    .navbar .sub-menu:after {
        border-top: 6px solid transparent;
        border-left: none;
        border-right: 6px solid #fff;
        border-bottom: 6px solid transparent;
        left: 10px;
        top: 11px;
        left: -6px;
    }
}

Upvotes: 3

John Montgomery
John Montgomery

Reputation: 1965

I've used a bit of jQuery:

// Add hover effect to menus
jQuery('ul.nav li.dropdown').hover(function() {
  jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn();
}, function() {
  jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut();
});

Upvotes: 136

stinaq
stinaq

Reputation: 1284

This is probably a stupid idea, but to just remove the arrow pointing down, you can delete the

<b class="caret"></b>

This does nothing for the up pointing one, though...

Upvotes: 6

Andres I Perez
Andres I Perez

Reputation: 75409

I created a pure on hover dropdown menu based on the latest (v2.0.2) Bootstrap framework that has support for multiple submenus and thought I'd post it for future users:

body {
  padding-top: 60px;
  padding-bottom: 40px;
}

.sidebar-nav {
  padding: 9px 0;
}

.dropdown-menu .sub-menu {
  left: 100%;
  position: absolute;
  top: 0;
  visibility: hidden;
  margin-top: -1px;
}

.dropdown-menu li:hover .sub-menu {
  visibility: visible;
}

.dropdown:hover .dropdown-menu {
  display: block;
}

.nav-tabs .dropdown-menu,
.nav-pills .dropdown-menu,
.navbar .dropdown-menu {
  margin-top: 0;
}

.navbar .sub-menu:before {
  border-bottom: 7px solid transparent;
  border-left: none;
  border-right: 7px solid rgba(0, 0, 0, 0.2);
  border-top: 7px solid transparent;
  left: -7px;
  top: 10px;
}

.navbar .sub-menu:after {
  border-top: 6px solid transparent;
  border-left: none;
  border-right: 6px solid #fff;
  border-bottom: 6px solid transparent;
  left: 10px;
  top: 11px;
  left: -6px;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.2/css/bootstrap.min.css" rel="stylesheet" />

<div class="navbar navbar-fixed-top">
  <div class="navbar-inner">
    <div class="container-fluid">
      <a data-target=".nav-collapse" data-toggle="collapse" class="btn btn-navbar">
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </a>
      <a href="#" class="brand">Project name</a>
      <div class="nav-collapse">
        <ul class="nav">
          <li class="active"><a href="#">Home</a></li>
          <li><a href="#">Link</a></li>
          <li><a href="#">Link</a></li>
          <li><a href="#">Link</a></li>
          <li class="dropdown">
            <a data-toggle="dropdown" class="dropdown-toggle" href="#">Dropdown <b class="caret"></b></a>
            <ul class="dropdown-menu">
              <li>
                <a href="#">2-level Dropdown <i class="icon-arrow-right"></i></a>
                <ul class="dropdown-menu sub-menu">
                  <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 class="nav-header">Nav header</li>
                  <li><a href="#">Separated link</a></li>
                  <li><a href="#">One more separated link</a></li>
                </ul>
              </li>
              <li><a href="#">Another action</a></li>
              <li><a href="#">Something else here</a></li>
              <li class="divider"></li>
              <li class="nav-header">Nav header</li>
              <li><a href="#">Separated link</a></li>
              <li><a href="#">One more separated link</a></li>
            </ul>
          </li>
        </ul>
        <form action="" class="navbar-search pull-left">
          <input type="text" placeholder="Search" class="search-query span2">
        </form>
        <ul class="nav pull-right">
          <li><a href="#">Link</a></li>
          <li class="divider-vertical"></li>
          <li class="dropdown">
            <a class="#" href="#">Menu</a>
          </li>
        </ul>
      </div>
      <!-- /.nav-collapse -->
    </div>
  </div>
</div>

<hr>

<ul class="nav nav-pills">
  <li class="active"><a href="#">Regular link</a></li>
  <li class="dropdown">
    <a href="#" data-toggle="dropdown" class="dropdown-toggle">Dropdown <b class="caret"></b></a>
    <ul class="dropdown-menu" id="menu1">
      <li>
        <a href="#">2-level Menu <i class="icon-arrow-right"></i></a>
        <ul class="dropdown-menu sub-menu">
          <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 class="nav-header">Nav header</li>
          <li><a href="#">Separated link</a></li>
          <li><a href="#">One more separated link</a></li>
        </ul>
      </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>
  </li>
  <li class="dropdown">
    <a href="#">Menu</a>
  </li>
  <li class="dropdown">
    <a href="#">Menu</a>
  </li>
</ul>

Demo

Upvotes: 615

Ahmad
Ahmad

Reputation: 455

<!DOCTYPE html>
<html>
<head>
<style>
.dropbtn {
    background-color: #4CAF50;
    color: white;
    padding: 16px;
    font-size: 16px;
    border: none;
    cursor: pointer;
}

.dropdown {
    position: relative;
    display: inline-block;
}

.dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
}

.dropdown-content a {
    color: black;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
}

.dropdown-content a:hover {background-color: #f1f1f1}

.dropdown:hover .dropdown-content {
    display: block;
}

.dropdown:hover .dropbtn {
    background-color: #3e8e41;
}
</style>
</head>
<body>

<h2>Hoverable Dropdown</h2>
<p>Move the mouse over the button to open the dropdown menu.</p>

<div class="dropdown">
  <button class="dropbtn">Dropdown</button>
  <div class="dropdown-content">
    <a href="#">Link 1</a>
    <a href="#">Link 2</a>
    <a href="#">Link 3</a>
  </div>
</div>

</body>
</html>

Upvotes: 1

shiva krishna
shiva krishna

Reputation: 222

 <ul class="nav navbar-nav">
        <li class="active"><a href="#">Link</a></li>
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
          <ul class="dropdown-menu">
            <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>
            <li class="divider"></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <script>
        $('ul.nav li.dropdown').hover(function() {
        $(this).find('.dropdown-menu').stop(true, 
        true).delay(200).fadeIn(500);
        }, function() {
        $(this).find('.dropdown-menu').stop(true, 
        true).delay(200).fadeOut(500);
        });
      </script>

Upvotes: 0

Related Questions