'Custom responsive navbar (priority nav) using Bootstrap 5 and no JQuery

Trying to create a Bootstrap 5 custom responsive navbar (priority nav) with a "show More..." option using Vanilla JS, as I have dozens of menu-items and I can't use jQuery

As you might know, bootstrap navbars doesn't adopt to the screen widths and it gets broken into the next line introduced by overflowing menus. I want to stop the menu overflow to the next line by having them move to the "More..." menu-item using bootstrap 5 and Vanilla Javascript

custom responsive navbar mockup

I did try to modify this answer but had no luck, as it's written with Bootstrap 3 and uses JQuery, which I can't use

var elemWidth, fitCount, varWidth = 0,
  ctr,
  $menu = $("ul#menu"),
  $collectedSet;

ctr = $menu.children().length;
$menu.children().each(function() {
  varWidth += $(this).outerWidth();
});

collect();
$(window).resize(collect);

function collect() {
  elemWidth = $menu.width();
  fitCount = Math.floor((elemWidth / varWidth) * ctr) - 1;
  $menu.children().css({
    "display": "block",
    "width": "auto"
  });
  $collectedSet = $menu.children(":gt(" + fitCount + ")");
  $("#submenu").empty().append($collectedSet.clone());
  $collectedSet.css({
    "display": "none",
    "width": "0"
  });
}
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

div.menuwrap {
  position: relative;
  background-color: #ccc;
  height: 48px;
  overflow: visible;
}

ul.menu {
  height: 48px;
  max-width: 80%;
  overflow: hidden;
}

ul.menu>li {
  display: block;
  float: left;
  height: auto;
  white-space: nowrap;
  padding: 4px 8px;
}

ul.collect {
  position: absolute;
  right: 0;
  top: 0;
  padding: 4px 8px;
  overflow: visible;
}

ul.collect ul.dropdown-menu {
  right: 0;
  left: auto;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<div class="menuwrap">
  <ul id="menu" class="nav nav-pills menu">
    <li class="active"><a href="#">Dashboard</a></li>
    <li><a href="#">Docs</a></li>
    <li><a href="#">Docs 2</a></li>
    <li><a href="#">Docs 3</a></li>
    <li><a href="#">Docs 4</a></li>
    <li><a href="#">Data</a></li>
    <li><a href="#">iWeb</a></li>
    <li><a href="#">Program</a></li>
  </ul>
  <ul class="nav nav-pills collect">
    <li class="dropdown">
      <a role="button" href="#" data-toggle="dropdown" class="dropdown-toggle">
          More <span class="caret"></span>
        </a>
      <ul id="submenu" class="dropdown-menu"></ul>
    </li>
  </ul>
</div>


Solution 1:[1]

In case anyone had the same issue, I managed to do it in this jsfiddle using the Priority Nav plugin

// https://gijsroge.github.io/priority-nav.js/

/*
 * priority-nav - v1.0.11 | (c) 2016 @gijsroge | MIT license
 * Repository: https://github.com/gijsroge/priority-navigation.git
 * Description: Priority+ pattern navigation that hides menu items if they don't fit on screen.
 * Demo: http://gijsroge.github.io/priority-nav.js/
 */
! function(a, b) {
  "function" == typeof define && define.amd ? define("priorityNav", b(a)) : "object" == typeof exports ? module.exports = b(a) : a.priorityNav = b(a)
}(window || this, function(a) {
  "use strict";

  function b(a, b, c) {
    var d;
    return function() {
      var e = this,
        f = arguments,
        g = function() {
          d = null, c || a.apply(e, f)
        },
        h = c && !d;
      clearTimeout(d), d = setTimeout(g, b), h && a.apply(e, f)
    }
  }
  var c, d, e, f, g, h, i, j, k, l = {},
    m = [],
    n = !!document.querySelector && !!a.addEventListener,
    o = {},
    p = 0,
    q = 0,
    r = 0,
    s = {
      initClass: "js-priorityNav",
      mainNavWrapper: "nav",
      mainNav: "ul",
      navDropdownClassName: "nav__dropdown",
      navDropdownToggleClassName: "nav__dropdown-toggle",
      navDropdownLabel: "...",
      navDropdownBreakpointLabel: "menu",
      breakPoint: 500,
      throttleDelay: 50,
      offsetPixels: 0,
      count: !0,
      moved: function() {},
      movedBack: function() {}
    },
    t = function(a, b, c) {
      if ("[object Object]" === Object.prototype.toString.call(a))
        for (var d in a) Object.prototype.hasOwnProperty.call(a, d) && b.call(c, a[d], d, a);
      else
        for (var e = 0, f = a.length; f > e; e++) b.call(c, a[e], e, a)
    },
    u = function(a, b) {
      for (var c = b.charAt(0); a && a !== document; a = a.parentNode)
        if ("." === c) {
          if (a.classList.contains(b.substr(1))) return a
        } else if ("#" === c) {
        if (a.id === b.substr(1)) return a
      } else if ("[" === c && a.hasAttribute(b.substr(1, b.length - 2))) return a;
      return !1
    },
    v = function(a, b) {
      var c = {};
      return t(a, function(b, d) {
        c[d] = a[d]
      }), t(b, function(a, d) {
        c[d] = b[d]
      }), c
    },
    w = function(a, b) {
      if (a.classList) a.classList.toggle(b);
      else {
        var c = a.className.split(" "),
          d = c.indexOf(b);
        d >= 0 ? c.splice(d, 1) : c.push(b), a.className = c.join(" ")
      }
    },
    x = function(a, b) {
      return k = document.createElement("span"), h = document.createElement("ul"), i = document.createElement("button"), i.innerHTML = b.navDropdownLabel, i.setAttribute("aria-controls", "menu"), h.setAttribute("aria-hidden", "true"), a.querySelector(g).parentNode !== a ? void console.warn("mainNav is not a direct child of mainNavWrapper, double check please") : (a.insertAfter(k, a.querySelector(g)), k.appendChild(i), k.appendChild(h), h.classList.add(b.navDropdownClassName), h.classList.add("priority-nav__dropdown"), i.classList.add(b.navDropdownToggleClassName), i.classList.add("priority-nav__dropdown-toggle"), k.classList.add(b.navDropdownClassName + "-wrapper"), k.classList.add("priority-nav__wrapper"), void a.classList.add("priority-nav"))
    },
    y = function(a) {
      var b = window.getComputedStyle(a),
        c = parseFloat(b.paddingLeft) + parseFloat(b.paddingRight);
      return a.clientWidth - c
    },
    z = function() {
      var a = document,
        b = window,
        c = a.compatMode && "CSS1Compat" === a.compatMode ? a.documentElement : a.body,
        d = c.clientWidth,
        e = c.clientHeight;
      return b.innerWidth && d > b.innerWidth && (d = b.innerWidth, e = b.innerHeight), {
        width: d,
        height: e
      }
    },
    A = function(a) {
      e = y(a), j = a.querySelector(h).parentNode === a ? a.querySelector(h).offsetWidth : 0, f = E(a) + o.offsetPixels, r = z().width
    };
  l.doesItFit = function(a) {
    o = v(s, c || {});
    var d = 0 === a.getAttribute("instance") ? d : o.throttleDelay;
    p++, b(function() {
      var b = a.getAttribute("instance");
      for (A(a); f >= e && a.querySelector(g).children.length > 0 || r < o.breakPoint && a.querySelector(g).children.length > 0;) l.toDropdown(a, b), A(a, b), r < o.breakPoint && D(a, b, o.navDropdownBreakpointLabel);
      for (; e >= m[b][m[b].length - 1] && r > o.breakPoint;) l.toMenu(a, b), r > o.breakPoint && D(a, b, o.navDropdownLabel);
      m[b].length < 1 && (a.querySelector(h).classList.remove("show"), D(a, b, o.navDropdownLabel)), a.querySelector(g).children.length < 1 ? (a.classList.add("is-empty"), D(a, b, o.navDropdownBreakpointLabel)) : a.classList.remove("is-empty"), B(a, b)
    }, d)()
  };
  var B = function(a, b) {
      m[b].length < 1 ? (a.querySelector(i).classList.add("priority-nav-is-hidden"), a.querySelector(i).classList.remove("priority-nav-is-visible"), a.classList.remove("priority-nav-has-dropdown"), a.querySelector(".priority-nav__wrapper").setAttribute("aria-haspopup", "false")) : (a.querySelector(i).classList.add("priority-nav-is-visible"), a.querySelector(i).classList.remove("priority-nav-is-hidden"), a.classList.add("priority-nav-has-dropdown"), a.querySelector(".priority-nav__wrapper").setAttribute("aria-haspopup", "true"))
    },
    C = function(a, b) {
      a.querySelector(i).setAttribute("priorityNav-count", m[b].length)
    },
    D = function(a, b, c) {
      a.querySelector(i).innerHTML = c
    };
  l.toDropdown = function(a, b) {
    a.querySelector(h).firstChild && a.querySelector(g).children.length > 0 ? a.querySelector(h).insertBefore(a.querySelector(g).lastElementChild, a.querySelector(h).firstChild) : a.querySelector(g).children.length > 0 && a.querySelector(h).appendChild(a.querySelector(g).lastElementChild), m[b].push(f), B(a, b), a.querySelector(g).children.length > 0 && o.count && C(a, b), o.moved()
  }, l.toMenu = function(a, b) {
    a.querySelector(h).children.length > 0 && a.querySelector(g).appendChild(a.querySelector(h).firstElementChild), m[b].pop(), B(a, b), a.querySelector(g).children.length > 0 && o.count && C(a, b), o.movedBack()
  };
  var E = function(a) {
      for (var b = a.childNodes, c = 0, d = 0; d < b.length; d++) 3 !== b[d].nodeType && (isNaN(b[d].offsetWidth) || (c += b[d].offsetWidth));
      return c
    },
    F = function(a, b) {
      window.attachEvent ? window.attachEvent("onresize", function() {
        l.doesItFit && l.doesItFit(a)
      }) : window.addEventListener && window.addEventListener("resize", function() {
        l.doesItFit && l.doesItFit(a)
      }, !0), a.querySelector(i).addEventListener("click", function() {
        w(a.querySelector(h), "show"), w(this, "is-open"), w(a, "is-open"), -1 !== a.className.indexOf("is-open") ? a.querySelector(h).setAttribute("aria-hidden", "false") : (a.querySelector(h).setAttribute("aria-hidden", "true"), a.querySelector(h).blur())
      }), document.addEventListener("click", function(c) {
        u(c.target, "." + b.navDropdownClassName) || c.target === a.querySelector(i) || (a.querySelector(h).classList.remove("show"), a.querySelector(i).classList.remove("is-open"), a.classList.remove("is-open"))
      }), document.onkeydown = function(a) {
        a = a || window.event, 27 === a.keyCode && (h.classList.remove("show"), i.classList.remove("is-open"), d.classList.remove("is-open"))
      }
    };
  Element.prototype.remove = function() {
    this.parentElement.removeChild(this)
  }, NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
    for (var a = 0, b = this.length; b > a; a++) this[a] && this[a].parentElement && this[a].parentElement.removeChild(this[a])
  }, l.destroy = function() {
    o && (document.documentElement.classList.remove(o.initClass), k.remove(), o = null, delete l.init, delete l.doesItFit)
  }, n && "undefined" != typeof Node && (Node.prototype.insertAfter = function(a, b) {
    this.insertBefore(a, b.nextSibling)
  });
  var G = function(a) {
    var b = a.charAt(0);
    return "." === b || "#" === b ? !1 : !0
  };
  return l.init = function(a) {
    if (o = v(s, a || {}), !n && "undefined" == typeof Node) return void console.warn("This browser doesn't support priorityNav");
    if (!G(o.navDropdownClassName) || !G(o.navDropdownToggleClassName)) return void console.warn("No symbols allowed in navDropdownClassName & navDropdownToggleClassName. These are not selectors.");
    var b = document.querySelectorAll(o.mainNavWrapper);
    t(b, function(a) {
      return m[q] = [], a.setAttribute("instance", q++), (d = a) ? (g = o.mainNav, a.querySelector(g) ? (x(a, o), h = "." + o.navDropdownClassName, a.querySelector(h) ? (i = "." + o.navDropdownToggleClassName, a.querySelector(i) ? (F(a, o), void l.doesItFit(a)) : void console.warn("couldn't find the specified navDropdownToggle element")) : void console.warn("couldn't find the specified navDropdown element")) : void console.warn("couldn't find the specified mainNav element")) : void console.warn("couldn't find the specified mainNavWrapper element")
    }), p++, document.documentElement.classList.add(o.initClass)
  }, l
});

var nav = priorityNav.init();
/*
 * Core styles for PriorityNav.js
 * These styles are not optional and should always be included
 *
 * Free to use under the MIT License.
 * http://twitter.com/GijsRoge
 */

.priority-nav {
  white-space: nowrap;
  /*
    * Makes sure the menu's are inline-block so they don't take up
    * the entire width of its parent. This will break the plugin.
    */
}

.priority-nav ul {
  display: inline-block;
}

.priority-nav li {
  display: inline-block;
}

.priority-nav-has-dropdown .priority-nav__dropdown-toggle {
  position: relative;
}

.priority-nav__wrapper {
  position: relative;
}

.priority-nav__dropdown {
  position: absolute;
  visibility: hidden;
}

.priority-nav__dropdown.show {
  visibility: visible;
}

.priority-nav__dropdown-toggle {
  visibility: hidden;
  position: absolute;
}

.priority-nav-is-visible {
  visibility: visible;
}

.priority-nav-is-hidden {
  visibility: hidden;
}


/* klk */

nav {
  margin: 7rem 0;
  padding: 0 4rem;
  min-width: 250px;
  position: relative;
  white-space: nowrap;
  max-width: 950px;
  -webkit-animation: resize 4s 1 cubic-bezier(0.4, 0, 0.2, 1);
  animation: resize 4s 1 cubic-bezier(0.4, 0, 0.2, 1);
  -webkit-animation-delay: 1s;
  animation-delay: 1s;
}

@media (max-width: 650px) {
  nav {
    padding: 0;
    min-width: 100px;
  }
  nav .wrapper {
    padding: 0 1rem;
  }
}

nav ul {
  display: inline-block;
  list-style-type: none;
  padding: 0;
  margin: 0;
}

nav li {
  display: inline-block;
}

nav li:first-child a {
  padding-left: 0;
}

@media (max-width: 650px) {
  nav li:first-child a {
    padding-left: 0.5rem;
  }
}

nav a {
  display: inline-block;
  padding: 4rem 2rem;
  font-weight: 700;
}

@media (max-width: 650px) {
  nav a {
    padding: 2rem 1rem;
  }
}

nav .knob {
  cursor: ew-resize;
  position: absolute;
  right: 0;
  top: 50%;
  -webkit-transform: translateY(-50%) translateX(50%);
  transform: translateY(-50%) translateX(50%);
}

@media (max-width: 1000px) {
  nav .knob {
    display: none;
  }
}

.nav__dropdown {
  padding: 2rem;
  white-space: nowrap;
  top: 80%;
  right: 0;
  background-color: #404040;
  transition: 300ms cubic-bezier(0.25, 2, 0.25, 1);
  -webkit-transform-origin: center top;
  transform-origin: center top;
  -webkit-transform: rotateX(-30deg);
  transform: rotateX(-30deg);
  opacity: 0;
}

.nav__dropdown.show {
  -webkit-transform: rotateX(0deg);
  transform: rotateX(0deg);
  opacity: 1;
  visibility: visible;
  box-shadow: 0 0 20px 0 rgba(49, 49, 49, 0.25);
  transition: 300ms cubic-bezier(0.25, 2, 0.25, 1), box-shadow 1000ms cubic-bezier(0.25, 2, 0.25, 1);
}

.nav__dropdown a:focus {
  box-shadow: 0 0 3px white, inset 0 0 3px white;
}

@media (max-width: 650px) {
  .nav__dropdown {
    right: auto;
    left: -50vw;
  }
  .nav__dropdown:after {
    left: auto;
  }
}

.nav__dropdown:after {
  content: "";
  display: block;
  position: absolute;
  height: 0;
  width: 0;
  border-bottom: 6px solid #068df6;
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  content: "";
  top: -6px;
  right: 4rem;
}

.nav__dropdown-wrapper {
  display: inline-block;
  -webkit-perspective: 500px;
  perspective: 500px;
  background-color: black;
}

@media (max-width: 650px) {
  .nav__dropdown-wrapper {
    position: static !important;
  }
}

.nav__dropdown li {
  display: block;
}

.nav__dropdown li:first-child a {
  padding-left: 2rem;
}

.nav__dropdown a {
  display: inline-block;
  padding: 0.5rem 2rem;
  font-weight: 400;
}

nav {
  max-width: 100%;
  background-color: #404040;
}

.nav-link {
  color: white;
  font-family: Roboto, Arial, sans-serif;
  font-size: 1rem;
  font-weight: 1400;
  line-height: 1.428571429;
  margin: 0;
  text-align: left;
  background-color: #404040;
  line-height: 1.42857143;
  padding: 0;
}

.be-top-header .navbar-nav>li.nav-item>a.nav-link:hover {
  color: #c2c2c2;
}

.be-top-header .navbar-nav>li.nav-item.show>a:hover {
  color: #4285f4;
}

.be-color-header .be-top-header .navbar-collapse ul li a:hover,
.be-color-header .be-sub-navigation .navbar-collapse ul li a:hover i {
  color: #545a58;
}

.menu_nav_bar_custom .navbar-nav>li.nav-item>a.nav-link {
  padding: 0.2rem 15px;
}

.be-top-header .navbar-nav>li.nav-item.show>a,
.be-sub-navigation .navbar-nav>li.nav-item.show>a:focus {
  color: white;
}

@media only screen and (min-width: 992px) {
  .navbar {
    padding: 1;
  }
  .navbar .navbar-brand {
    padding: 0 0.7em;
  }
  .navbar .navbar-nav .nav-link {
    padding: 1em 0;
  }
  .navbar .navbar-nav .nav-item {
    margin: 0 1em;
  }
}

.navbar .navbar-nav .nav-item {
  position: relative;
}

.navbar .navbar-nav .nav-item::after {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
  background-color: #c2c2c2;
  width: 0%;
  content: "";
  height: 3px;
}

.navbar .navbar-nav .nav-item:hover::after {
  width: 100%;
}

.dropdown-menu {
  position: absolute !important;
}

.nav-link {
  padding: 0.5rem 0.5rem;
}

.dropdown-menu {
  position: absolute !important;
}

.nav-link {
  padding: 0.5rem 0.5rem;
}
<script src="https://raw.githubusercontent.com/gijsroge/priority-navigation/master/dist/priority-nav.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<nav class="navbar navbar-expand fixed-top be-top-header top_nav_bar_custom">


  <ul class="mr-auto">
   <li class="nav-item">
      <a class="nav-link active" aria-current="page" href="#">Home</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="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
        Dropdown link
      </a>
      <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
        <li><a class="dropdown-item" href="#">Action</a></li>
        <li><a class="dropdown-item" href="#">Another action</a></li>
        <li><a class="dropdown-item" href="#">Something else here</a></li>
  </ul>
</nav>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1