Vertical menu collapsible v3
by Plippie Plop
HTML
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<div id="page-container">
<div id="page-header"><button type="button" class="btn toggle-side-menu" data-menu="#side-menu-left"><i class="fa fa-bars"></i></button>
<nav class="header-menu">
<ul>
<li><a href="#">The first menu item</a></li>
<li><a href="#">Menu 2</a></li>
<li><a href="#">Menu 3</a></li>
</ul>
</nav>
<nav class="header-menu">
<ul>
<li><a href="#">Menu 4</a></li>
<li><a href="#">Menu 5</a></li>
<li><a href="#">Menu 6</a></li>
<li class="more hidden" data-width="80"></li>
</ul>
</nav>
</div>
<div id="main-container">
<div id="side-menu-left" class="has-footer">
<header>
<h3>Header</h3>
</header>
<div class="side-content">
<nav class="collapsible-menu">
<ul class="menu">
<li class="first-menu"><a>The top menu item has a very long text</a></li>
<li class="first-menu"><a>Item 2</a>
<ul>
<li><a>item 2 sub 1</a></li>
<li><a>Item 2 sub 2</a></li>
</ul>
</li>
<li class="first-menu"><a>Item 3</a>
<ul>
<li><a>item 3 sub 1</a></li>
<li><a>Item 3 sub 2</a>
<ul>
<li><a>Item 2 sub-sub 1</a></li>
<li><a>Item 2 sub-sub 2</a></li>
</ul>
</li>
<li><a>Item 3 sub 3</a>
<li><a>Item 3 sub 4</a>
<li><a>Item 3 sub 5</a>
<li><a>Item 3 sub 6</a>
</ul>
</li>
<li class="first-menu"><a>Item 4</a>
<ul>
<li><a>item 4 sub 1</a></li>
<li><a>Item 4 sub 2</a>
<ul>
<li><a>Item 4 sub-sub 1</a></li>
...
CSS
::-webkit-scrollbar {
width: 0.5rem;
}
::-webkit-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(0, 0, 0, 0.4);
border-radius: 0.25rem;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(0, 0, 0, 0.8);
}
:root {
--page-header-height:54px;
--menu-bg: rgb(250, 250, 250);
--menu-item-bg: rgb(255, 255, 255);
--menu-item-hover-bg: rgb(242, 242, 245);
--menu-item-active-bg: rgb(124 192 251);
--menu-item-active-hover-bg: rgb(171 214 251);
--menu-color: rgb(20, 20, 20);
--menu-active-color: rgb(255, 255, 255);
--menu-border-radius: 0;
--menu-sub-height: 30em;
--w-header-bg: rgb(52, 121, 180);
--transition-01: cubic-bezier(0.4, 0.1, 0.7, 0.95);
--transition-02: cubic-bezier(0.1, 0.7, 0.6, 0.9);
/* using font awesome 4.7 for chevron icons */
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body,
body>header {
height: 100%;
margin: 0;
padding: 0;
}
/* respect viewport height */
body {
font-family: system-ui, Sans-Serif;
}
ul,
li {
list-style: none;
position: relative;
outline: none;
}
#page-container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 0fr 1fr;
background-color: rgb(255, 255, 255);
height: 100%;
}
#page-header {
display: grid;
grid-template-columns:50px 1fr 1fr;
background-color: var(--w-header-bg);
}
#main-container {
display: grid;
min-height: 0;
}
.toggle-side-menu {
cursor: pointer;
background-color: rgba(0, 0, 0, 0.2);
color: white;
border: 0;
outline: 0;
padding: 0.5rem 1.2rem;
}
.toggle-side-menu:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.header-menu,
.header-menu ul {
display: flex;
align-items: stretch;
}
.header-menu li {
position: relative;
}
.header-menu li a {
padding: 1rem 0.8rem;
text-decoration: none;
display: flex;
align-items: stretch;
color: white;
white-space: nowrap;
}
.header-menu li a:hover {
background-color: rgba(0, 0, 0,...
JavaScript
class CollapsibleMenu {
constructor(menuContainer, options = {
exclusiveActive: true
}) {
this.menu = menuContainer;
this.menuItems = this.menu ? this.menu.querySelectorAll('li') : [];
this.exclusiveActive = options.exclusiveActive;
if (!this.menu || !this.menuItems.length) {
console.warn("No menu or list items found");
return;
}
this.init();
}
init() {
// Check for submenus
this.menuItems.forEach(item => {
const submenu = item.querySelector('ul');
if (submenu) {
item.classList.add('has-sub');
}
});
// Bind click event using event delegation
this.menu.addEventListener('click', (e) => {
const clickedElement = e.target;
// Check if the clicked element is an anchor tag inside an li
if (clickedElement.tagName === 'A' && clickedElement.closest('li')) {
e.preventDefault();
const menuItem = clickedElement.closest('li');
// Toggle 'active' class for the clicked menu item
menuItem.classList.toggle('active');
// Toggle 'active' class for parent menu items
if (this.exclusiveActive) {
this.menuItems.forEach(item => {
const isAncestor = item.contains(menuItem);
if (item !== menuItem && !isAncestor) {
item.classList.remove('active');
}
});
} else {
// If exclusiveActive is false, remove 'active' class from siblings
const siblings = menuItem.parentElement.children;
for (const sibling of siblings) {
if (sibling !== menuItem) {
sibling.classList.remove('active');
}
}
}
}
});
}
}
document.addEventListener('DOMContentLoaded', function() {
const sideMenu = document.querySelector(".collapsible-menu");
// If the element exists, instantiate MyClass and bind it to the element
if (sideMenu) {
const menuClass = new...