Vertical menu collapsible
by Plippie Plop
HTML
<nav id="list">
<ul class="menu">
<li class="first-menu"><a>Item 1</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>
<li><a>Item 4 sub-sub 2</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
CSS
@import url('https://fonts.googleapis.com/css2?family=Oswald&display=swap');
:root {
--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-border-radius: 0.25rem;
}
* {
box-sizing: border-box;
}
::-webkit-scrollbar {
width: 0.2rem;
}
::-webkit-scrollbar-track {
background: rgba(0, 0, 0, 0);
}
::-webkit-scrollbar-thumb {
background: rgba(100, 100, 100, 0.4);
border-radius: 2px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(100, 100, 100, 0.8);
}
ul,
li {
margin: 0;
padding: 0;
list-style: none;
position: relative;
outline: none;
overflow: hidden;
}
#list {
display: flex;
position: relative;
width: fit-content;
font-family: "Oswald";
background-color: lightgrey;
padding: 0.2rem;
border-radius: var(--menu-border-radius);
min-width:200px;
}
.menu{
width:100%;
}
.menu ul {
max-height: 0;
transition: max-height 0.2s;
height: auto;
}
.menu li.open>ul {
transition: max-height 0.2s;
max-height: 15em;
overflow-y: auto;
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
border-top: 1px solid rgba(0, 0, 0, 0.3);
}
.menu a {
display: flex;
border-bottom: 1px solid rgba(0, 0, 0, 0.2);
padding: 0.5rem 1.5rem 0.5rem 0.5rem;
cursor: pointer;
position: relative;
background-color: var(--menu-item-bg);
}
.menu a:hover {
background-color: var(--menu-item-hover-bg);
}
.menu li a.active {
background-color: var(--menu-item-active-bg);
}
.menu a.active:hover {
background-color: var(--menu-item-active-bg);
}
.menu .has-sub > ul> li> a{
padding-left:1rem;
}
.menu .has-sub .has-sub > ul >li> a{
padding-left:2rem;
}
.menu li:last-of-type > a{
border-bottom:0;
}
.menu>.first-menu:first-of-type>a{
border-radius: var(--border-radius) var(--border-radius) 0 0;
}
.menu>.first-menu:last-of-type>a,
.menu>.first-menu:last-of-type...
JavaScript
const list = $("#list");
list.find('a').each(function(idx, elm) {
console.log(idx, elm);
$(elm).closest('li').attr('data-menu-index', idx);
if ($(elm).closest('li').children('ul').length) {
$(elm).closest('li').addClass('has-sub');
}
});
list.find('.active').parents('li').addClass('open').find('> a').addClass('active');
list.on('click', 'a', function(e) {
let $this = $(this);
if (!$this.hasClass('active')) {
console.log("not active");
list.find('.open').removeClass('open');
list.find('.active').removeClass('active');
$this.addClass('active').parents('li').addClass('open').find('> a').addClass('active');
} else {
console.log("IS active");
$this.removeClass('active').closest('li').removeClass('open');
$this.children('li').removeClass('open');
}
});