[html] How to implement a Navbar Dropdown Hover in Bootstrap v4?

I am a bit confused on the new bootstrap version since they changed dropdown menus to divs:

<nav class="navbar navbar-toggleable-md navbar-light bg-faded">
  <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
  <a class="navbar-brand" href="#">Navbar</a>
  <div class="collapse navbar-collapse" id="navbarNavDropdown">
    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Features</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="#">Pricing</a>
      </li>
      <li class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" href="http://example.com" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
          Dropdown link
        </a>
        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
          <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>
      </li>
    </ul>
  </div>
</nav>

Do you guys have any idea to get a hover dropdown in the Dropdown link in that snippet without adding additional script code (only css and script from bootstrap)? I already saw the bootstrap css classes and I can't relate with the ones in bootstrap V3 (I accomplish this without adding jquery in V3).

This question is related to html css twitter-bootstrap

The answer is


Simple, CSS only solution:

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

When clicked, it will still get the class show toggled to it (and will remain open when no longer hovered).


To get around this properly is to use events and properties reserved to pointer based devices: jQuery's mouseenter, mouseleave and :hover. Should work smoothly, intuitively, while not interfering at all with how the dropdown works on touch based devices. Try it out, let me know if it works for you:

Complete jQuery solution (touch untouched):

Pre v4.1.2 solution (deprecated):

$('body').on('mouseenter mouseleave','.dropdown',function(e){
  var _d=$(e.target).closest('.dropdown');
  if (e.type === 'mouseenter')_d.addClass('show');
  setTimeout(function(){
    _d.toggleClass('show', _d.is(':hover'));
    $('[data-toggle="dropdown"]', _d).attr('aria-expanded',_d.is(':hover'));
  },300);
});

_x000D_
_x000D_
$('body').on('mouseenter mouseleave','.dropdown',function(e){_x000D_
  var _d=$(e.target).closest('.dropdown');_x000D_
  if (e.type === 'mouseenter')_d.addClass('show');_x000D_
  setTimeout(function(){_x000D_
    _d.toggleClass('show', _d.is(':hover'));_x000D_
    $('[data-toggle="dropdown"]', _d).attr('aria-expanded',_d.is(':hover'));_x000D_
  },300);_x000D_
});_x000D_
_x000D_
/* this is not needed, just prevents page reload when a dd link is clicked */_x000D_
$('.dropdown a').on('click tap', e => e.preventDefault())
_x000D_
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>_x000D_
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>_x000D_
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>_x000D_
_x000D_
<nav class="navbar navbar-toggleable-md navbar-light bg-faded">_x000D_
  <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">_x000D_
    <span class="navbar-toggler-icon"></span>_x000D_
  </button>_x000D_
  <a class="navbar-brand" href>Navbar</a>_x000D_
  <div class="collapse navbar-collapse" id="navbarNavDropdown">_x000D_
    <ul class="navbar-nav">_x000D_
      <li class="nav-item active">_x000D_
        <a class="nav-link" href>Home <span class="sr-only">(current)</span></a>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href>Features</a>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href>Pricing</a>_x000D_
      </li>_x000D_
      <li class="nav-item dropdown">_x000D_
        <a class="nav-link dropdown-toggle" href id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">_x000D_
          Dropdown link_x000D_
        </a>_x000D_
        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">_x000D_
          <a class="dropdown-item" href>Action</a>_x000D_
          <a class="dropdown-item" href>Another action</a>_x000D_
          <a class="dropdown-item" href>Something else here</a>_x000D_
        </div>_x000D_
      </li>_x000D_
    </ul>_x000D_
  </div>_x000D_
</nav>
_x000D_
_x000D_
_x000D_


v4.1.2 shiplist introduced this change to how dropdowns work, making the solution above no longer work.
Here's the up to date solution for having the dropdown open on hover in v4.1.2 and above:

function toggleDropdown (e) {
  const _d = $(e.target).closest('.dropdown'),
    _m = $('.dropdown-menu', _d);
  setTimeout(function(){
    const shouldOpen = e.type !== 'click' && _d.is(':hover');
    _m.toggleClass('show', shouldOpen);
    _d.toggleClass('show', shouldOpen);
    $('[data-toggle="dropdown"]', _d).attr('aria-expanded', shouldOpen);
  }, e.type === 'mouseleave' ? 300 : 0);
}

$('body')
  .on('mouseenter mouseleave','.dropdown',toggleDropdown)
  .on('click', '.dropdown-menu a', toggleDropdown);

_x000D_
_x000D_
function toggleDropdown (e) {_x000D_
  const _d = $(e.target).closest('.dropdown'),_x000D_
      _m = $('.dropdown-menu', _d);_x000D_
  setTimeout(function(){_x000D_
    const shouldOpen = e.type !== 'click' && _d.is(':hover');_x000D_
    _m.toggleClass('show', shouldOpen);_x000D_
    _d.toggleClass('show', shouldOpen);_x000D_
    $('[data-toggle="dropdown"]', _d).attr('aria-expanded', shouldOpen);_x000D_
  }, e.type === 'mouseleave' ? 300 : 0);_x000D_
}_x000D_
_x000D_
$('body')_x000D_
  .on('mouseenter mouseleave','.dropdown',toggleDropdown)_x000D_
  .on('click', '.dropdown-menu a', toggleDropdown);_x000D_
_x000D_
/* not needed, prevents page reload for SO example on menu link clicked */_x000D_
$('.dropdown a').on('click tap', e => e.preventDefault())
_x000D_
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>_x000D_
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>_x000D_
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>_x000D_
_x000D_
<nav class="navbar navbar-expand-lg navbar-light bg-light">_x000D_
  <a class="navbar-brand" href="#">Navbar</a>_x000D_
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">_x000D_
    <span class="navbar-toggler-icon"></span>_x000D_
  </button>_x000D_
_x000D_
  <div class="collapse navbar-collapse" id="navbarSupportedContent">_x000D_
    <ul class="navbar-nav mr-auto">_x000D_
      <li class="nav-item active">_x000D_
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href="#">Link</a>_x000D_
      </li>_x000D_
      <li class="nav-item dropdown">_x000D_
        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">_x000D_
          Dropdown_x000D_
        </a>_x000D_
        <div class="dropdown-menu" aria-labelledby="navbarDropdown">_x000D_
          <a class="dropdown-item" href="#">Action</a>_x000D_
          <a class="dropdown-item" href="#">Another action</a>_x000D_
          <div class="dropdown-divider"></div>_x000D_
          <a class="dropdown-item" href="#">Something else here</a>_x000D_
        </div>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link disabled" href="#">Disabled</a>_x000D_
      </li>_x000D_
    </ul>_x000D_
    <form class="form-inline my-2 my-lg-0">_x000D_
      <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">_x000D_
      <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>_x000D_
    </form>_x000D_
  </div>_x000D_
</nav>
_x000D_
_x000D_
_x000D_


Important note: If using the jQuery solution, it is important to remove the CSS one (or the dropdown won't close when .dropdown-toggle is clicked or when an menu option is clicked).


Just Add this simple css code in your style-sheet and you are ready to go.

.dropdown:hover > .dropdown-menu {
    display: block;
}
.dropdown > .dropdown-toggle:active {
    /*Without this, clicking will make it sticky*/
    pointer-events: none;
}

Bootstrap 4 CSS-only

None of the CSS only answers work entirely. Either the dropdown menu stays open after click, or there is a gap that makes the dropdown menu hide before you can reach the menu links to click.

Here's the simple CSS only solution:

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

Remove data-toggle=dropdown from the HTML markup to prevent the dropdown staying open in click. Use mt-0 (margin-top:0) to eliminate the gap above the menu, and make it possible to hover the menu items.

Demo https://www.codeply.com/go/awyU7VTIJf


Complete Code:

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

   <nav class="navbar navbar-expand-lg navbar-light bg-light">
      ..
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav mr-auto">
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown">
              Dropdown
            </a>
            <div class="dropdown-menu mt-0" aria-labelledby="navbarDropdown">
              <a class="dropdown-item" href="#">Action</a>
              <a class="dropdown-item" href="#">Another action</a>
              <div class="dropdown-divider"></div>
              <a class="dropdown-item" href="#">Something else here</a>
            </div>
          </li>
        </ul>
      </div>
    </nav>   

Andrei's "complete" jQuery+CSS solution has the right intent, but it's verbose and still incomplete. Incomplete because while it probably covers all the necessary DOM changes, it's missing the firing of custom events. Verbose because it's wheel-reinventing when Bootstrap already provides the dropdown() method, which does everything.

So the correct, DRY solution, which does not rely on the CSS hack often repeated among other answers, is just jQuery:

$('body').on('mouseover mouseout', '.dropdown', function(e) {
    $(e.target).dropdown('toggle');
});

Bootstrap's functionality appears to have changed slightly since v4 has been released. The .dropdown-menu item appears to also now get the .show class in addition to the .dropdown. I adapted Andrei's answer to also toggle the class on the .dropdown-menu. Note that the CSS is no longer necessary and the HTML is the same except I updated the links to the current versions and the nav class changed to navbar-expand-md.

_x000D_
_x000D_
$('body').on('mouseenter mouseleave', '.dropdown', function (e) {_x000D_
    var dropdown = $(e.target).closest('.dropdown');_x000D_
    var menu = $('.dropdown-menu', dropdown);_x000D_
    dropdown.addClass('show');_x000D_
    menu.addClass('show');_x000D_
    setTimeout(function () {_x000D_
        dropdown[dropdown.is(':hover') ? 'addClass' : 'removeClass']('show');_x000D_
        menu[dropdown.is(':hover') ? 'addClass' : 'removeClass']('show');_x000D_
    }, 300);_x000D_
});
_x000D_
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">_x000D_
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>_x000D_
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>_x000D_
<nav class="navbar navbar-expand-md navbar-light bg-faded">_x000D_
  <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">_x000D_
    <span class="navbar-toggler-icon"></span>_x000D_
  </button>_x000D_
  <a class="navbar-brand" href="#">Navbar</a>_x000D_
  <div class="collapse navbar-collapse" id="navbarNavDropdown">_x000D_
    <ul class="navbar-nav">_x000D_
      <li class="nav-item active">_x000D_
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href="#">Features</a>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href="#">Pricing</a>_x000D_
      </li>_x000D_
      <li class="nav-item dropdown">_x000D_
        <a class="nav-link dropdown-toggle" href="http://example.com" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">_x000D_
          Dropdown link_x000D_
        </a>_x000D_
        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">_x000D_
          <a class="dropdown-item" href="#">Action</a>_x000D_
          <a class="dropdown-item" href="#">Another action</a>_x000D_
          <a class="dropdown-item" href="#">Something else here</a>_x000D_
        </div>_x000D_
      </li>_x000D_
    </ul>_x000D_
  </div>_x000D_
</nav>
_x000D_
_x000D_
_x000D_


Bootstrap v4 Solution - jQuery based, but better than a pure css solution

This ensures that you can still follow top level link clicks and is compatible with mobile.

This was built with desktop and mobile in mind. Fell free to wrap the jQuery with a conditional that checks if the window width is greater than 768px.

jQuery

/** Dropdown on hover */
$(".nav-link.dropdown-toggle").hover( function () {
    // Open up the dropdown
    $(this).removeAttr('data-toggle'); // remove the data-toggle attribute so we can click and follow link
    $(this).parent().addClass('show'); // add the class show to the li parent
    $(this).next().addClass('show'); // add the class show to the dropdown div sibling
}, function () {
    // on mouseout check to see if hovering over the dropdown or the link still
    var isDropdownHovered = $(this).next().filter(":hover").length; // check the dropdown for hover - returns true of false
    var isThisHovered = $(this).filter(":hover").length;  // check the top level item for hover
    if(isDropdownHovered || isThisHovered) {
        // still hovering over the link or the dropdown
    } else {
        // no longer hovering over either - lets remove the 'show' classes
        $(this).attr('data-toggle', 'dropdown'); // put back the data-toggle attr
        $(this).parent().removeClass('show');
        $(this).next().removeClass('show');
    }
});
// Check the dropdown on hover
$(".dropdown-menu").hover( function () {
}, function() {
    var isDropdownHovered = $(this).prev().filter(":hover").length; // check the dropdown for hover - returns true of false
    var isThisHovered= $(this).filter(":hover").length;  // check the top level item for hover
    if(isDropdownHovered || isThisHovered) {
        // do nothing - hovering over the dropdown of the top level link
    } else {
        // get rid of the classes showing it
        $(this).parent().removeClass('show');
        $(this).removeClass('show');
    }
});

CSS

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

Hoverable dropdown without losing functionality of popper.js for bootstrap 4 only

Javascript

$('.dropdown-hoverable').hover(function(){
    $(this).children('[data-toggle="dropdown"]').click();
}, function(){
    $(this).children('[data-toggle="dropdown"]').click();
});

HTML

<nav class="nav">
  <li class="nav-item dropdown dropdown-hoverable">
    <a class="nav-link dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#">Menu link</a>
    <ul class="dropdown-menu">
    </ul>
  </li>
</nav>

I had already used and styled a navbar when I was requested to change it to a hover interaction instead, so ended up with this as a fix using jQuery.

function bootstrapHoverMenu (bp = 768) {

  // close all dropdowns that are open
    $('body').click( function (e) {
    $('.dropdown-menu.show').removeClass('show');
  });

  // show dropdown for the link clicked
  $('.nav-item').hover(function (e) {
    $('.dropdown-menu.show').removeClass('show');
    if(( $(window).width() >= bp )) {
      $dd = $(this).find('.dropdown-menu');
      $dd.addClass('show');
    }
  });

  // get href for top level link if clicked and open
  $('.dropdown').click(function (e) {
    if( $(window).width() < bp ) {
      $('.dropdown-menu').css({'display': 'none'});
    }
    $href = $(this).find('.nav-link').attr('href');
    window.open($href, '_self');
  });
}

$(document).ready( function() {
   // when page ready run the fix
   bootstrapHoverMenu();
});

Downside is mobile only has top level links.


This solution switches on and off

<script>
$(document).ready(function() {
  // close all dropdowns that are open
  $('body').click(function(e) {
      $('.nav-item.show').removeClass('show');
      //$('.nav-item.clicked').removeClass('clicked');
      $('.dropdown-menu.show').removeClass('show');
  });

  $('.nav-item').click( function(e) {
    $(this).addClass('clicked')
  });

  // show dropdown for the link clicked
  $('.nav-item').hover(function(e) {
      if ($('.nav-item.show').length < 1) {
        $('.nav-item.clicked').removeClass('clicked');
      }
      if ($('.nav-item.clicked').length < 1) {
          $('.nav-item.show').removeClass('show');
          $('.dropdown-menu.show').removeClass('show');
          $dd = $(this).find('.dropdown-menu');
          $dd.parent().addClass('show');
          $dd.addClass('show');
      }
  });
});</script>

To disable the hover for lg sized collapse menus add

if(( $(window).width() >= 992 )) {

1. Remove data-toggle="dropdown" attribute (so click will not open dropdown menu)

2. Add :hover pseudo-class to show dropdown-menu

_x000D_
_x000D_
.dropdown:hover .dropdown-menu {display: block;}
_x000D_
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>_x000D_
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>_x000D_
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>_x000D_
_x000D_
<nav class="navbar navbar-toggleable-md navbar-light bg-faded">_x000D_
  <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">_x000D_
    <span class="navbar-toggler-icon"></span>_x000D_
  </button>_x000D_
  <a class="navbar-brand" href="#">Navbar</a>_x000D_
  <div class="collapse navbar-collapse" id="navbarNavDropdown">_x000D_
    <ul class="navbar-nav">_x000D_
      <li class="nav-item active">_x000D_
        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>_x000D_
      </li>_x000D_
      <li class="nav-item dropdown">_x000D_
        <a class="nav-link dropdown-toggle" href="http://example.com" id="navbarDropdownMenuLink" aria-haspopup="true" aria-expanded="false">_x000D_
          Dropdown link_x000D_
        </a>_x000D_
        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">_x000D_
          <a class="dropdown-item" href="#">Action</a>_x000D_
          <a class="dropdown-item" href="#">Another action</a>_x000D_
          <a class="dropdown-item" href="#">Something else here</a>_x000D_
        </div>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href="#">Features</a>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href="#">Pricing</a>_x000D_
      </li>_x000D_
    </ul>_x000D_
  </div>_x000D_
</nav>
_x000D_
_x000D_
_x000D_


CSS solutions not working properly on touch device

I found that any CSS solutions made the menu stay open on touch devices, they didn't collapse anymore.

So I read the article: https://www.brianshim.com/webtricks/drop-down-menus-on-ios-and-android/ (by Brian Shim)
Very useful! It states that a touch device always first checks the existence of a hover class on an element.

But: by using jQuery .show() you introduce a style attribute (display:block;) that makes the menu open up on first touch. Now the menu has opened without the bootstrap 'show' class. If a user chooses a link from the dropdown menu it works perfectly. But if a user decides to close the menu without using it he has to tap twice to close the menu: At the first tap the original bootstrap 'show' class gets attached so the menu opens up again, at the second tap the menu closes due to normal bootstrap behaviour (removal of 'show' class).

To prevent this I used the article: https://codeburst.io/the-only-way-to-detect-touch-with-javascript-7791a3346685 (by David Gilbertson)

He has some very handy ways of detecting touch or hover devices.

So, combined the two authors with a bit jQuery of my own:

$(window).one('mouseover', function(){
      window.USER_CAN_HOVER = true;
      if(USER_CAN_HOVER){
          jQuery('#navbarNavDropdown ul li.dropdown').on("mouseover", function() {
             var $parent = jQuery(this);
             var $dropdown = $parent.children('ul');

             $dropdown.show(200,function() { 
               $parent.mouseleave(function() {
                 var $this = jQuery(this);
                 $this.children('ul').fadeOut(200);
               });
             });
          });
      };

}); Check once if a device allows a hover event. If it does, introduce the possibility to hover using .show(). If the device doesn't allow a hover event, the .show() never gets introduced so you get natural bootstrap behaviour on touch device.

Be sure to remove any CSS regarding menu hover classes.

Took me three days :) so I hope it helps some of you.


I think this simply just work with bootstrap 4, i adding in inline but you always can bind event from script.

  <a 
onmouseover="$('#navbarDropdownMenuLink').dropdown('toggle')"
class="nav-link dropdown-toggle" 
href="http://example.com" 
id="navbarDropdownMenuLink" 
data-toggle="dropdown" 
aria-haspopup="true" 
aria-expanded="false">
      Dropdown link
    </a>

Google brought me here but... The examples provided work if the dropdown menu is overlaping (at least by 1px) with its parent when show. If not, it loses focus and nothing works as intended.

Here is a working solution with jQuery and Bootstrap 4.5.2 :

$('li.nav-item').mouseenter(function (e) {

        e.stopImmediatePropagation();

        if ($(this).hasClass('dropdown')) {

            // target element containing dropdowns, show it
            $(this).addClass('show');
            $(this).find('.dropdown-menu').addClass('show');

            // Close dropdown on mouseleave
            $('.dropdown-menu').mouseleave(function (e) {
                e.stopImmediatePropagation();
                $(this).removeClass('show');
            });

            // If you have a prenav above, this clears open dropdowns (since you probably will hover the nav-item going up and it will reopen its dropdown otherwise)
            $('#prenav').off().mouseenter(function (e) {
                e.stopImmediatePropagation();
                $('.dropdown-menu').removeClass('show');
            });

        } else {
            // unset open dropdowns if hover is on simple nav element
            $('.dropdown-menu').removeClass('show');
        }
    });

I couldn't find here the full solution. So, it's my one which works with Bootstrap v4.4.1 and has the next benefits:

  • A click on the dropdown-toggle works as a normal nav link.

  • Supports any nesting level of dropdown menus.

  • Bootstrap 4 {show/shown/hide/hidden}.bs.dropdown events work well.

     // Toggles a B4 dropdown-menu to a given state.
     const toggleDropdownElement = ($dropdown, shouldOpen = false) => {
       const $dropdownToggle = $dropdown.children('[data-toggle="dropdown"], a');
       const $dropdownMenu = $dropdown.children('.dropdown-menu');
    
       // Change the dropdown menu. It's similar to B4 Dropdown.show()/.hide(), see /bootstrap/js/src/dropdown.js.
       if (shouldOpen) {
         $dropdown.trigger('show.bs.dropdown');
         $dropdownToggle.attr('aria-expanded', true).focus();
         $dropdownMenu.addClass('show');
         $dropdown.addClass('show').trigger($.Event('shown.bs.dropdown', $dropdownMenu[0]));
       } else {
         $dropdown.trigger('hide.bs.dropdown');
         $dropdownToggle.attr('aria-expanded', false);
         $dropdownMenu.removeClass('show');
         $dropdown.removeClass('show').trigger($.Event('hidden.bs.dropdown', $dropdownMenu[0]));
       }
     };
    
     // Toggles a B4 dropdown-menu with any nesting level.
     const toggleDropdown = (event) => {
       const $dropdown = $(event.target).closest('.dropdown');
       const $parentDropdownMenu = $dropdown.closest('.dropdown-menu');
       const shouldOpen = event.type !== 'click' && $dropdown.is(':hover');
    
       // If the dropdown was closed already, break the 'mouseleave' event cascade.
       if (!shouldOpen && !$dropdown.hasClass('show')) return;
    
       // Change the current dropdown menu (last nested).
       toggleDropdownElement($dropdown, shouldOpen);
    
       // We have to close the dropdown menu tree if it was a click or the menu was leave at all.
       if (event.type === 'click' || $parentDropdownMenu.length && !$parentDropdownMenu.is(':hover')) {
         $dropdown.parents('.dropdown').each((index, element) => {
           toggleDropdownElement($(element), false);
         });
       }
     };
    
     if (viewport && viewport.is('>=xl')) {
       $('body')
         .on('mouseenter mouseleave', '.dropdown', toggleDropdown)
         .on('click', '.dropdown-menu a', toggleDropdown);
    
       // Disable the default B4's click. Other words, change a dropdown-toggle to a normal nav link.
       $(document).off('click.bs.dropdown', '[data-toggle="dropdown"]');
       $(document).off('click.bs.dropdown.data-api', '[data-toggle="dropdown"]'); // Not sure about it.
     }
    

If you don't use ES6 just change arrow functions to the old function style.

Thanks, @tao for your example, it was helpful for me.

Code related links: B4 Dropdown Events, viewport (Responsive Bootstrap Toolkit), WP Bootstrap Navwalker.


(June 2020) I found this solution and I thought I should post it here:

Bootstrap version: 4.3.1

The CSS part:

.navbar .nav-item:not(:last-child) {
  margin-right: 35px;
}

.dropdown-toggle::after {
   transition: transform 0.15s linear;
}

.show.dropdown .dropdown-toggle::after {
  transform: translateY(3px);
}

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

The jQuery part:

const $dropdown = $(".dropdown");
const $dropdownToggle = $(".dropdown-toggle");
const $dropdownMenu = $(".dropdown-menu");
const showClass = "show";

$(window).on("load resize", function() {
  if (this.matchMedia("(min-width: 768px)").matches) {
    $dropdown.hover(
      function() {
        const $this = $(this);
        $this.addClass(showClass);
        $this.find($dropdownToggle).attr("aria-expanded", "true");
        $this.children($dropdownMenu).addClass(showClass);
      },
      function() {
        const $this = $(this);
        $this.removeClass(showClass);
        $this.find($dropdownToggle).attr("aria-expanded", "false");
        $this.children($dropdownMenu).removeClass(showClass);
      }
    );
  } else {
    $dropdown.off("mouseenter mouseleave");
  }
});

Source: https://webdesign.tutsplus.com/tutorials/how-to-make-the-bootstrap-navbar-dropdown-work-on-hover--cms-33840


Neither of the top solutions worked for me.

This works perfectly, keeps submenus open while browsing, add uses the native Bootstrap javascript.

// Mouse over
$('body').on('mouseover', '.dropdown', function(e) { 
    $(this).children('.dropdown-toggle').dropdown('show');
});

// Mouse leave
$('body').on('mouseleave', '.dropdown', function(e) { 
    $(this).children('.dropdown-toggle').dropdown('hide');
});

CSS and Desktop only solution

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

I use bootstrap 4.0.0 since we want to simulate .show to hover event, it simply easy. just add all styles in .dropdown.show .dropdown-menu to the :hover. like this:

.dropdown:hover>.dropdown-menu {
  opacity: 1;
  visibility: visible;
  transform: translate3d(0px, 0px, 0px);
}

_x000D_
_x000D_
$('body').on('mouseenter mouseleave','.dropdown',function(e){_x000D_
  var _d=$(e.target).closest('.dropdown');_x000D_
  if (e.type === 'mouseenter')_d.addClass('show');_x000D_
  setTimeout(function(){_x000D_
    _d.toggleClass('show', _d.is(':hover'));_x000D_
    $('[data-toggle="dropdown"]', _d).attr('aria-expanded',_d.is(':hover'));_x000D_
  },300);_x000D_
});_x000D_
_x000D_
/* this is not needed, just prevents page reload when a dd link is clicked */_x000D_
$('.dropdown a').on('click tap', e => e.preventDefault())
_x000D_
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>_x000D_
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>_x000D_
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js"></script>_x000D_
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js"></script>_x000D_
_x000D_
<nav class="navbar navbar-toggleable-md navbar-light bg-faded">_x000D_
  <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">_x000D_
    <span class="navbar-toggler-icon"></span>_x000D_
  </button>_x000D_
  <a class="navbar-brand" href>Navbar</a>_x000D_
  <div class="collapse navbar-collapse" id="navbarNavDropdown">_x000D_
    <ul class="navbar-nav">_x000D_
      <li class="nav-item active">_x000D_
        <a class="nav-link" href>Home <span class="sr-only">(current)</span></a>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href>Features</a>_x000D_
      </li>_x000D_
      <li class="nav-item">_x000D_
        <a class="nav-link" href>Pricing</a>_x000D_
      </li>_x000D_
      <li class="nav-item dropdown">_x000D_
        <a class="nav-link dropdown-toggle" href id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">_x000D_
          Dropdown link_x000D_
        </a>_x000D_
        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">_x000D_
          <a class="dropdown-item" href>Action</a>_x000D_
          <a class="dropdown-item" href>Another action</a>_x000D_
          <a class="dropdown-item" href>Something else here</a>_x000D_
        </div>_x000D_
      </li>_x000D_
    </ul>_x000D_
  </div>_x000D_
</nav>
_x000D_
_x000D_
_x000D_


<div style="width: 100%; overflow: scroll;"><table class="table table-striped table-bordered" style="font-size:12px">


Questions with html tag:

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment Angular 6: saving data to local storage Vue.js get selected option on @change Bootstrap 4 multiselect dropdown How to add bootstrap in angular 6 project? Angular 5 Button Submit On Enter Key Press Angular 5, HTML, boolean on checkbox is checked How to render string with html tags in Angular 4+? bootstrap 4 file input doesn't show the file name How can I execute a python script from an html button? Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width Failed to load resource: the server responded with a status of 404 (Not Found) css Change arrow colors in Bootstraps carousel Bootstrap 4 Dropdown Menu not working? CSS Grid Layout not working in IE11 even with prefixes How to prevent page from reloading after form submit - JQuery Centering in CSS Grid Detecting real time window size changes in Angular 4 Angular 4 img src is not found (change) vs (ngModelChange) in angular Bootstrap 4: Multilevel Dropdown Inside Navigation Align the form to the center in Bootstrap 4 How to style a clicked button in CSS How do I change the font color in an html table? Redirecting to a page after submitting form in HTML Load json from local file with http.get() in angular 2 display: flex not working on Internet Explorer Scroll to element on click in Angular 4 How to extract svg as file from web page force css grid container to fill full screen of device How does the "position: sticky;" property work? HTML5 Video autoplay on iPhone Disable button in angular with two conditions? CSS hide scroll bar, but have element scrollable CSS grid wrapping How to load image (and other assets) in Angular an project? Flask - Calling python function on button OnClick event How can I make Bootstrap 4 columns all the same height? Wrapping a react-router Link in an html button

Questions with css tag:

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width Font Awesome 5 font-family issue Failed to load resource: the server responded with a status of 404 (Not Found) css CSS class for pointer cursor How and where to use ::ng-deep? Styling mat-select in Angular Material What is the difference between CSS and SCSS? iPhone X / 8 / 8 Plus CSS media queries Change arrow colors in Bootstraps carousel Bootstrap 4 Dropdown Menu not working? Add class to an element in Angular 4 CSS Grid Layout not working in IE11 even with prefixes Search input with an icon Bootstrap 4 Bootstrap 4 - Inline List? Centering in CSS Grid Bootstrap 4, how to make a col have a height of 100%? Equal height rows in CSS Grid Layout Bootstrap 4: Multilevel Dropdown Inside Navigation Align the form to the center in Bootstrap 4 Customize Bootstrap checkboxes How to style a clicked button in CSS How can I get the height of an element using css only display: flex not working on Internet Explorer force css grid container to fill full screen of device How does the "position: sticky;" property work? bootstrap 4 row height Prevent content from expanding grid items Bootstrap 4 File Input CSS hide scroll bar, but have element scrollable CSS grid wrapping Bootstrap 4 Change Hamburger Toggler Color How can I make Bootstrap 4 columns all the same height? How to hide collapsible Bootstrap 4 navbar on click Bootstrap 4 Center Vertical and Horizontal Alignment Cannot read property 'style' of undefined -- Uncaught Type Error How to window.scrollTo() with a smooth effect Vertical Align Center in Bootstrap 4 How to implement a Navbar Dropdown Hover in Bootstrap v4? CSS change button style after click What is correct media query for IPad Pro? How do I specify row heights in CSS Grid layout?

Questions with twitter-bootstrap tag:

Bootstrap 4: responsive sidebar menu to top navbar CSS class for pointer cursor How to install popper.js with Bootstrap 4? Change arrow colors in Bootstraps carousel Search input with an icon Bootstrap 4 bootstrap 4 responsive utilities visible / hidden xs sm lg not working bootstrap.min.js:6 Uncaught Error: Bootstrap dropdown require Popper.js Bootstrap 4 - Inline List? Bootstrap 4, how to make a col have a height of 100%? Bootstrap 4: Multilevel Dropdown Inside Navigation Align the form to the center in Bootstrap 4 Customize Bootstrap checkboxes Angular 4: How to include Bootstrap? bootstrap 4 row height Bootstrap 4 File Input How can I center an image in Bootstrap? Bootstrap 4 Change Hamburger Toggler Color How can I make Bootstrap 4 columns all the same height? Center the content inside a column in Bootstrap 4 col align right How to hide collapsible Bootstrap 4 navbar on click Bootstrap 4 Center Vertical and Horizontal Alignment Vertical Align Center in Bootstrap 4 How to implement a Navbar Dropdown Hover in Bootstrap v4? `col-xs-*` not working in Bootstrap 4 Using media breakpoints in Bootstrap 4-alpha Bootstrap 4, How do I center-align a button? What is class="mb-0" in Bootstrap 4? Bootstrap 4 align navbar items to the right Bootstrap fullscreen layout with 100% height Bootstrap 4 img-circle class not working Bootstrap footer at the bottom of the page How to create a fixed sidebar layout with Bootstrap 4? How to include bootstrap css and js in reactjs app? Bootstrap date time picker How to change the bootstrap primary color? What is the '.well' equivalent class in Bootstrap 4 Bootstrap col-md-offset-* not working $(...).datepicker is not a function - JQuery - Bootstrap Failed to load resource 404 (Not Found) - file location error? Table column sizing How to add bootstrap to an angular-cli project How to get images in Bootstrap's card to be the same height/width? Stretch image to fit full container width bootstrap Bootstrap 4 card-deck with number of columns based on viewport Removing padding gutter from grid columns in Bootstrap 4 How to use Bootstrap in an Angular project? How to put a link on a button with bootstrap? Bootstrap get div to align in the center How to make Bootstrap 4 cards the same height in card-columns?