Author: | tomaszbujnowicz |
---|---|
Views Total: | 3,081 views |
Official Page: | Go to website |
Last Update: | April 16, 2021 |
License: | MIT |
Preview:

Description:
An animated multi-level accordion menu built with nested nav list and vanilla JavaScript.
How to use it:
1. The required markup structure for the nested accordion menu.
<div class="accordion-menu-wrapper active" id="menu-parent" data-accordion-wrapper> <nav role="navigation" class="accordion-menu"> <ul class="accordion-menu__list"> <li class="accordion-menu__item"> <a href="#menu-1" class="accordion-menu__link" data-accordion-menu> <span> Menu 1 Dropdown </span> <span class="accordion-menu__icon"></span> </a> <ul class="accordion-menu__sublist accordion-menu--hidden" id="menu-1"> <li> <a href="#" class="accordion-menu__sublink"> Child Menu 1 </a> </li> <li> <a href="#menu-1-1" class="accordion-menu__link" data-accordion-menu> <span> Child Menu 2 Dropdown </span> <span class="accordion-menu__icon"></span> </a> <ul class="accordion-menu__sublist accordion-menu--hidden" id="menu-1-1"> <li> <a href="#" class="accordion-menu__sublink"> Grand Child Menu 1 </a> </li> <li> <a href="#" class="accordion-menu__sublink"> Grand Child Menu 2 </a> </li> </ul> </li> </ul> </li> <li class="accordion-menu__item"> <a href="#menu-2" class="accordion-menu__link" data-accordion-menu> <span> Menu 2 Dropdown </span> <span class="accordion-menu__icon"></span> </a> <ul class="accordion-menu__sublist accordion-menu--hidden" id="menu-2"> <li> <a href="#" class="accordion-menu__sublink"> Child Menu 2 </a> </li> <li> <a href="#menu-2-1" class="accordion-menu__link" data-accordion-menu> <span> Child Menu 2 Dropdown </span> <span class="accordion-menu__icon"></span> </a> <ul class="accordion-menu__sublist accordion-menu--hidden" id="menu-2-1"> <li> <a href="#" class="accordion-menu__sublink"> Grand Child Menu 1 </a> </li> <li> <a href="#" class="accordion-menu__sublink"> Grand Child Menu 2 </a> </li> </ul> </li> </ul> </li> <li class="accordion-menu__item"> <a href="#" class="accordion-menu__link"> Submenu item </a> </li> </ul> </nav> </div>
2. The basic styling of the nested accordion menu.
.accordion-menu--hidden { display: none; } .accordion-menu__list, .accordion-menu__sublist { list-style-type: none; margin: 0; padding: 0; } .accordion-menu__list { border-top: 1px #eee solid; } .accordion-menu__link { display: flex; align-items: center; justify-content: space-between; padding-top: 1rem; padding-bottom: 1rem; border-bottom: 1px #eee solid; } .accordion-menu__icon { position: relative; width: 16px; height: 16px; transition: .2s all; } .accordion-menu__icon:before, .accordion-menu__icon:after { content: ""; display: block; background-color: #333; position: absolute; top: 50%; left: 0; transition: .35s; width: 100%; height: 2px; } .accordion-menu__icon:before { transform: translateY(-50%); } .accordion-menu__icon:after { transform: translateY(-50%) rotate(90deg); } .accordion-menu--active .accordion-menu__icon:before { transform: translateY(-50%) rotate(-90deg); opacity: 0; } .accordion-menu--active .accordion-menu__icon:after { transform: translateY(-50%) rotate(0); } .accordion-menu__sublist { margin-left: 1.25rem; } .accordion-menu__sublink { display: block; padding-top: 1rem; padding-bottom: 1rem; border-bottom: 1px #eee solid; } .accordion-menu-nav { display: flex; align-items: center; justify-content: space-between; padding-bottom: 1rem; overflow: scroll; } .accordion-menu-nav__link:not(:last-child) { margin-right: 1rem; } .accordion-menu-wrapper { display: none; } .accordion-menu-wrapper.active { display: block; }
3. The main function.
var accordionMenu = function () { /** * Element.closest() polyfill * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill */ if (!Element.prototype.closest) { if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; } Element.prototype.closest = function (s) { var el = this; var ancestor = this; if (!document.documentElement.contains(el)) return null; do { if (ancestor.matches(s)) return ancestor; ancestor = ancestor.parentElement; } while (ancestor !== null); return null; }; } // Listen for click on the document // Accordiom menu functionality document.addEventListener('click', function (event) { // Bail if our clicked element doesn't match var trigger = event.target.closest('[data-accordion-menu]'); if (!trigger) return; // Get the target content var target = document.querySelector(trigger.hash); if (!target) return; // Prevent default link behavior event.preventDefault(); // Toggle our content target.classList.toggle('accordion-menu--hidden'); // Toggle trigger class trigger.classList.toggle('accordion-menu--active'); }); // Listen for click on the document // Accordion parent menu functionality document.addEventListener('click', function (event) { // Bail if our clicked element doesn't match var trigger = event.target.closest('[data-accordion-menu-nav]'); if (!trigger) return; // Get the target content var target = document.querySelector(trigger.hash); if (!target) return; // Prevent default link behavior event.preventDefault(); // If the content is already expanded, collapse it and quit if (target.classList.contains('active')) { target.classList.remove('active'); return; } // Get all open accordion content, loop through it, and close it var accordions = document.querySelectorAll('[data-accordion-wrapper]'); for (var i = 0; i < accordions.length; i++) { accordions[i].classList.remove('active'); } // Toggle our content target.classList.toggle('active'); }); };
4. Activate the nested accordion menu.
accordionMenu();