skip to Main Content

I’m trying to create a multi-level dropdown menu using Bootstrap. By default, the dropdowns should align to the right side, but if there’s not enough space, they should switch to align to the left.

The problem I’m facing is that the inner dropdown menus sometimes extend beyond the right side of the screen, especially when there’s not enough space.

Here’s the relevant code:

HTML and CSS:

$(document).ready(function() {
  $('.nav-item.dropdown').on('mouseenter', function() {
    var $dropdownMenu = $(this).find('.dropdown-menu');
    var rect = $dropdownMenu[0].getBoundingClientRect();

    if (rect.right > window.innerWidth) {
      $dropdownMenu.addClass('dropdown-menu-end');
    } else {
      $dropdownMenu.removeClass('dropdown-menu-end');
    }
  });
});
<style>body {
  font-family: Verdana, Geneva, Tahoma, sans-serif;
}

.navbar {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  background-color: dimgrey;
  width: 100%;
}

.navbar-top {
  display: flex;
  justify-content: space-between;
  width: 100%;
  align-items: center;
}

.navbar-left {
  display: flex;
  align-items: center;
}

.navbar-brand {
  margin-right: 20px;
}

.switch-role-form {
  display: flex;
  align-items: center;
}

.switch-role {
  margin-right: 10px;
}

.welcome-message {
  color: blue;
  text-align: right;
}

.logout-button {
  top: 10px;
  right: 10px;
}

.navbar-nav {
  display: flex;
  justify-content: center;
  width: 100%;
  background-color: palevioletred;
}

.dropdown-menu li {
  position: relative;
}

.dropdown-menu .dropdown-submenu {
  display: none;
  position: absolute;
  left: 100%;
  top: -7px;
}

.dropdown-submenu-left {
  right: 100%;
  left: auto;
}

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

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

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

.navbar-expand-lg {
  width: 100%;
  display: flex;
  justify-content: center;
}

.dropdown-menu-end {
  left: auto;
  right: 100%;
}

</style>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dropdown Menu Alignment</title>
  <style>
    /* Add your CSS here */
  </style>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>

<body>
  <div class="navbar">
    <nav class="navbar navbar-expand-lg bg-body-tertiary">
      <div class="container-fluid">
        <ul class="navbar-nav">
          <li class="nav-item dropdown">
            <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                            Menu Item
                        </a>
            <ul class="dropdown-menu">
              <li>
                <a class="dropdown-item" href="#">Submenu Item »</a>
                <ul class="dropdown-menu dropdown-submenu">
                  <li><a class="dropdown-item" href="#">Submenu Item 1</a></li>
                  <li><a class="dropdown-item" href="#">Submenu Item 2</a></li>
                </ul>
              </li>
              <li><a class="dropdown-item" href="#">Another Item</a></li>
            </ul>
          </li>
        </ul>
      </div>
    </nav>
  </div>


</body>

The nested menu getting out of the screen

2

Answers


  1. You need to override .dropdown-menu[data-bs-popper] class css from left: 0; to right:0; as below:

    .dropdown-menu[data-bs-popper] {
      right: 0;
    }
    
    Login or Signup to reply.
  2. Your js code of rect.right do not include the dropdown-submenu element. So, you can try this code as below, to calculate the right boundary of the dropdown-submenu element and add or remove the class dropdown-menu-end:

    <script>
        document.querySelectorAll('.dropdown-menu').forEach(function (dropdownMenu) {
            dropdownMenu.addEventListener('mouseenter', function () {
                var subdropdownMenu = this.querySelector('.dropdown-submenu li:first-child');
                var $dropdownMenu1 = $(this).find('.dropdown-menu');
    
                if (subdropdownMenu) {
                    setTimeout(function () {
                        var rect = subdropdownMenu.getBoundingClientRect();
                        // console.log('subdropdownMenu rect.right:', rect.right);
                        // console.log('window.innerWidth:', window.innerWidth);
    
                        if (rect.right > window.innerWidth) {
                            $dropdownMenu1.addClass('dropdown-menu-end');
                            // console.log('Added dropdown-menu-end class');
                        } else {
                            $dropdownMenu1.removeClass('dropdown-menu-end');
                            // console.log('Removed dropdown-menu-end class');
                        }
                    }, 50); // Wait for 50 milliseconds before executing, ensuring that the elements have been fully rendered.
                } else {
                    // console.log('Submenu Item 1 not found.');
                }
            });
        });
    </script>
    

    Then change the css class .dropdown-menu-end as below:

    .dropdown-menu-end { 
        right: 100% !important; 
        left: auto !important;
    }
    

    Before:

    1enter image description here

    2enter image description here

    After:

    1enter image description here

    2enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search