Skip to content

Instantly share code, notes, and snippets.

@marcamos
Last active December 22, 2022 13:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcamos/7457412db0e544ff5cc8b68c4f4f3ae1 to your computer and use it in GitHub Desktop.
Save marcamos/7457412db0e544ff5cc8b68c4f4f3ae1 to your computer and use it in GitHub Desktop.
Simple, accessible, nav menu system that is keyboard friendly. Demo here: https://codepen.io/marcamos/pen/zYEXegV
const navButtonEl = '[aria-controls^="nav-menu-"]';
const navMenuEl = '[id^="nav-menu-"]';
const navButtons = Array.from(document.querySelectorAll(navButtonEl));
const navMenus = Array.from(document.querySelectorAll(navMenuEl));
const closeNavMenu = () => {
navButtons.forEach(button => {
button.setAttribute('aria-expanded', false);
});
navMenus.forEach(menu => {
menu.hidden = true;
});
}
navButtons.forEach(button => {
button.addEventListener('click', (el) => {
const associatedMenu = el.currentTarget.getAttribute('aria-controls');
navButtons.filter(el => el.getAttribute('aria-controls') != associatedMenu).forEach(otherbutton => {
otherbutton.setAttribute('aria-expanded', false);
});
navMenus.filter(el => el.id != associatedMenu).forEach(otherMenu => {
otherMenu.hidden = true;
});
const menuExpanded = button.getAttribute('aria-expanded') === 'true' || false;
button.setAttribute('aria-expanded', !menuExpanded);
const navMenu = document.getElementById(associatedMenu);
navMenu.hidden = !navMenu.hidden;
});
});
document.addEventListener('click', (el) => {
el.target.closest(navButtonEl) || el.target.closest(navMenuEl) ? '' : closeNavMenu();
});
document.addEventListener('keyup', (e) => {
e.key === "Escape" ? closeNavMenu() : '';
});
// The above assumes HTML like this:
// (note: each button / div pair is usually wrapped in a nav element and unordered list, etc. what you see below is the bare minimum)
//
// <button aria-controls="nav-menu-one" aria-expanded="false">Button One</button>
// <div id="nav-menu-one" hidden>
// stuff that is hidden until Button One is clicked
// </div>
//
// <button aria-controls="nav-menu-two" aria-expanded="false">Button Two</button>
// <div id="nav-menu-two" hidden>
// stuff that is hidden until Button Two is clicked
// </div>
//
// <button aria-controls="nav-menu-three" aria-expanded="false">Button Three</button>
// <div id="nav-menu-three" hidden>
// stuff that is hidden until Button Three is clicked
// </div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment