Regarding both of my above comments ...
@jeromebg ... link_value is an invalid attribute name. Please consider making use of a data-* global attribute and the DOM element's related dataset property instead ... something like e.g ... <a href="#" data-value="item 3"/> where each value then can be read like this ... linkElement.dataset.value.
@jeromebg ... the nested <ul/> markup is broken/invalid as well ... please fix it.
... and after having fixed the markup, one should make use of, as already suggested but not explicitly named, event-delegation.
The latter does not only mean listening at a common (outer) root node, it also means targeting the element/s of interest which, like the root-node, might have child element-nodes as well.
Thus one always has to query the element/s one is interested in. One mostly does achieve the result by utilizing the closest method of the event's target element.
And regarding another of the OP's requirements ...
... also add an 'active' class to the active element and his parent levels and remove the active class from the others ?
... the handler function would pass the currently identified link-element to a custom implemented function, thus forwarding such a special task and not taking care of such stuff by itself.
A function which marks the current menu item has to do following ...
identifying the menu-item node ... done by ...
const menuItem = elmLink.closest('li');
identifying the menu-root node ... done by ...
const menuRoot = menuItem.closest('ul.menu');
choosing the right selector for querying any list-item node which has a link-element (e.g. 'li:has(a[href])') and removing the intended class-name (and/or e.g. aria attributes) from each queried element.
adding the intended class-name (and/or e.g. aria attributes) to the list-item which has been identified as current.
It is not necessary to mark any list-item involved in another list-item's current state as current as well. The visual representation of such a state can be easily achieved by utilizing a functional CSS pseudo-class like :has()
function markCurrentMenuItem(elmLink) { const menuItem = elmLink.closest('li'); const menuRoot = menuItem.closest('ul.menu'); menuRoot .querySelectorAll('li:has(a[href])') .forEach(elm => { // elm.classList.remove('active'); elm.removeAttribute('aria-current'); }); // menuItem.classList.add('active'); menuItem.setAttribute('aria-current', 'true'); } document .querySelector('ul.menu') .addEventListener('click', evt => { const elmLink = evt.target.closest('a[href][data-value]') if (elmLink) { evt.preventDefault(); markCurrentMenuItem(elmLink); console.log({ value: elmLink.dataset.value }); } })
body { margin: 0; } ul { list-style: none; margin: 0; padding: 0 0 0 20px; } li { padding: 2px 0 2px 0; } a span { display: inline-block; padding: 0 20px; background-color: #f2ffa7; } /* li.active, */li[aria-current="true"] a > span { background-color: #b1d000; } /* ul:has(> li.active), */ul:has(> li[aria-current="true"]) { background-color: #bee8ff; } .as-console-wrapper { left: auto!important; width: 50%; min-height: 100%; }
<ul class="menu" role="menu" aria-label="Main Menu"> <li> <a href="#" data-value="item 1"> <span>First level Menu item 1</span> </a> </li> <li> <ul role="menu" aria-label="Second Level Menu"> <li> <a href="#" data-value="item 2-1"> <span>Second level Menu item 1</span> </a> </li> <li> <ul role="menu" aria-label="Third Level Menu"> <li> <a href="#" data-value="item 3-2-1"> <span>Third level Menu item 1</span> </a> </li> <li> <a href="#" data-value="item 3-2-2"> <span>Third level Menu item 2</span> </a> </li> <li> <a href="#" data-value="item 3-2-3"> <span>Third level Menu item 3</span> </a> </li> </ul> </li> <li> <a href="#" data-value="item 2-2"> <span>Second level Menu item 2</span> </a> </li> <li> <a href="#" data-value="item 2-3"> <span>Second level Menu item 3</span> </a> </li> </ul> </li> <li> <a href="#" data-value="item 2"> <span>First level Menu item 2</span> </a> </li> <li> <a href="#" data-value="item 3"> <span>First level Menu item 3</span> </a> </li> </ul>
querySelectorAll, then useaddEventListenerto bind you function to that event on that item?ulas a direct child of aul. If you want a nested list, you have to put your innerulinside ali..menuclass. developer.mozilla.org/en-US/docs/Learn/JavaScript/… mmm, just noticed MDN's hash links don't work in Chrome, but seem fine in Firefox..link_valueis an invalid attribute name. Please consider making use of adata-*global attribute and the DOM element's relateddatasetproperty instead ... something like e.g ...<a href="#" data-value="item 3"/>where each value then can be read like this ...linkElement.dataset.value.