Q: How do I toggle sub menu items on a navigation? I am working on an accessible navigation and would like to toggle submenu items on click using the same click handler but their closest respective sub-menu-items. (Any accessibility help is a bonus.) Is the only way to do this by setting an ID? If so, I would like this to be dynamic in the JS where the data-id is not hardcoded.


function handleSubmenuToggle() {
  console.log('click');
  document.querySelector('.sub-menu-items').style.display = 'block';
}
.nav-menu-container {
  background: black;
  color: white;
  font-size: 0.875rem;
  padding: 1.3125rem 1.875rem;
}

.menu-item {
  display: inline;
  padding: 0 0.75rem;
  position: relative;
}

.menu-item button {
  background-color: transparent;
  border: none;
  color: white;
}

.sub-menu-items {
  background: white;
  display: none;
  left: -25px;
  min-width: 183px;
  padding: 10px 0;
  position: absolute;
  top: 40px;
}

.sub-menu-items.show {
  display: block !important;
}

.sub-menu-items:after {
  width: 0;
  height: 0;
  border-left: 15px solid transparent;
  border-right: 15px solid transparent;
  border-bottom: 15px solid white;
  content: " ";
  position: absolute;
  top: -10px;
  left: 42%;
}

.sub-menu-items a {
  color: black;
  text-decoration: none;
  padding: .5rem 1rem;
  display: block;
}

.sub-menu-items a:hover {
  background-color: lightgray;
}
<header>
  <nav aria-label="Empower Reservation Navigation" class="nav-menu-container">
    <ul class="menu-items">
      <li class="menu-item slds-is-relative">
        <button aria-label='Toggle Button' aria-pressed='pressed' onclick="handleSubmenuToggle();">Menu Item 1 <i class="fa-solid fa-chevron-down"></i></button>
        <ul class="sub-menu-items">
          <li>
            <a href="#">Sub Menu Item</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 2</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 3</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 4</a>
          </li>
        </ul>
      </li>
      <li class="menu-item slds-is-relative">
        <button aria-label='Toggle Button' aria-pressed='pressed' onclick="handleSubmenuToggle()">Menu Item 2<i class="fa-solid fa-chevron-down"></i></button>
        <ul class="sub-menu-items">
          <li>
            <a href="#">Sub Menu Item</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 2</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 3</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 4</a>
          </li>
        </ul>
      </li>
      <li class="menu-item slds-is-relative">
        <button aria-label='Toggle Button' aria-pressed='pressed'>Tools <i class="fa-solid fa-chevron-down"></i></button>
        <ul class="sub-menu-items">
          <li>
            <a href="#">Sub Menu Item</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 2</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 3</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 4</a>
          </li>
        </ul>
      </li>
      <li class="menu-item slds-is-relative">
        <button aria-label='Toggle Button' aria-pressed='pressed'>Contact [Name] <i class="fa-solid fa-chevron-down"></i></button>
        <ul class="sub-menu-items">
          <li>
            <a href="#">Sub Menu Item</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 2</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 3</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 4</a>
          </li>
        </ul>
      </li>
    </ul>
  </nav>
</header>


Thanks in advance!
https://codepen.io/fawn-marie/pen/GRBobNX?editors=1111

A: W3 has some great examples how to implement WCAG features with ARIA attributes. A specific example could be found here: Navigation Menubar Example.
Give the <button> element two new aria attributes

*

*aria-haspopup to indicate that there is a flyout submenu;

*aria-expanded to provide information if the flyout is visible or not

By doing this you're giving the <button> the control over the state of the submenu. aria-expanded will now tell you the current state of the submenu. You can manipulate this state through JavaScript by setting the attribute value with Element.setAttribute.
Then you can open and close your submenu by styling the submenu based on the aria-expanded value. Since the button is a sibling of the submenu, you can use the sibling selector + to select the submenu whenever the button has a certain attribute, like this.
ul.submenu {
  display: none;
}

button[aria-expanded="true"] + ul.submenu {
  display: block;
}

The cool thing about this is that the <button> is the only authority over the submenu. From here you only have to listen for clicks on the button to toggle the aria-expanded state. The rest will be governed by CSS.
I suggest you look at the W3 link as it shows more attributes that you should use in this kind of structure to improve accessibility.


const subMenuToggles = document.querySelectorAll('.sub-menu-toggle');

document.addEventListener('click', event => {
  const subMenuToggle = event.target.closest('.sub-menu-toggle');
  if (subMenuToggle === null) {
    return;
  }
  
  for (const toggle of subMenuToggles) {
    if (toggle.hasAttribute('aria-haspopup')) {
      toggle.setAttribute('aria-expanded', 'false');
    }
  }
  
  if (!subMenuToggle.hasAttribute('aria-haspopup')) {
    return;
  }
  
  if (subMenuToggle.getAttribute('aria-expanded') === 'true') {
    subMenuToggle.setAttribute('aria-expanded', 'false');
  } else {
    subMenuToggle.setAttribute('aria-expanded', 'true');
  }
});
.nav-menu-container {
  background: black;
  color: white;
  font-size: 0.875rem;
  padding: 1.3125rem 1.875rem;
}

.menu-item {
  display: inline;
  padding: 0 0.75rem;
  position: relative;
}

.menu-item button {
  background-color: transparent;
  border: none;
  color: white;
}

.sub-menu-items {
  display: none;
  background: white;
  left: -25px;
  min-width: 183px;
  padding: 10px 0;
  position: absolute;
  top: 40px;
}

.sub-menu-toggle[aria-expanded="true"] + .sub-menu-items {
  display: block;
}

.sub-menu-items:after {
  width: 0;
  height: 0;
  border-left: 15px solid transparent;
  border-right: 15px solid transparent;
  border-bottom: 15px solid white;
  content: " ";
  position: absolute;
  top: -10px;
  left: 42%;
}

.sub-menu-items a {
  color: black;
  text-decoration: none;
  padding: .5rem 1rem;
  display: block;
}

.sub-menu-items a:hover {
  background-color: lightgray;
}
<header>
  <nav aria-label="Empower Reservation Navigation" class="nav-menu-container">
    <ul class="menu-items">
      <li class="menu-item slds-is-relative">
        <button class="sub-menu-toggle" aria-label='Toggle Button' aria-haspopup="true" aria-expanded="false">Menu Item 1 <i class="fa-solid fa-chevron-down"></i></button>

        <ul class="sub-menu-items">
          <li>
            <a href="#">Sub Menu Item</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 2</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 3</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 4</a>
          </li>
        </ul>
      </li>

      <li class="menu-item slds-is-relative">
        <button class="sub-menu-toggle" aria-label='Toggle Button' aria-haspopup="true" aria-expanded="false">Menu Item 2<i class="fa-solid fa-chevron-down"></i></button>

        <ul class="sub-menu-items">
          <li>
            <a href="#">Sub Menu Item</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 2</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 3</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 4</a>
          </li>
        </ul>
      </li>

      <li class="menu-item slds-is-relative">
        <button class="sub-menu-toggle" aria-label='Toggle Button' aria-haspopup="true" aria-expanded="false">Tools <i class="fa-solid fa-chevron-down"></i></button>
        
        <ul class="sub-menu-items">
          <li>
            <a href="#">Sub Menu Item</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 2</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 3</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 4</a>
          </li>
        </ul>
      </li>

      <li class="menu-item slds-is-relative">
        <button aria-label='Toggle Button' aria-pressed='pressed'>Contact [Name] <i class="fa-solid fa-chevron-down"></i></button>
        
        <ul class="sub-menu-items">
          <li>
            <a href="#">Sub Menu Item</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 2</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 3</a>
          </li>
          <li>
            <a href="#">Sub Menu Item 4</a>
          </li>
        </ul>
      </li>
    </ul>
  </nav>
</header>


