const MOBILE_BREAKPOINT_PX = 768; /** All focusable elements inside the menu (links). */ const getMenuFocusables = (menu) => menu.querySelectorAll('a[href]'); const mobileMenuHelper = () => { const mobileMenu = document.getElementById('nav-menu'); const mobileMenuToggleButton = document.getElementById('nav-toggle-button'); const mobileMenuToggle = document.querySelector('.nav-toggle-input'); const menuItems = mobileMenu.querySelectorAll('.nav-item'); const isMobile = () => window.innerWidth <= MOBILE_BREAKPOINT_PX; const syncMenuAriaHidden = () => { if (isMobile()) { const hidden = !mobileMenuToggle.checked; mobileMenu.setAttribute( 'aria-hidden', hidden ? 'true' : 'false', ); // inert removes the subtree from the a11y tree and makes descendants non-focusable if (hidden) { mobileMenu.setAttribute('inert', ''); } else { mobileMenu.removeAttribute('inert'); } setMenuFocusablesTabIndex(); } else { mobileMenu.removeAttribute('aria-hidden'); mobileMenu.removeAttribute('inert'); getMenuFocusables(mobileMenu).forEach((el) => { el.removeAttribute('tabindex'); }); } }; const setMenuFocusablesTabIndex = () => { const focusables = getMenuFocusables(mobileMenu); const hidden = !mobileMenuToggle.checked; focusables.forEach((el) => { if (hidden) { el.setAttribute('tabindex', '-1'); } else { el.removeAttribute('tabindex'); } }); }; const syncButtonAriaExpanded = () => { mobileMenuToggleButton.setAttribute( 'aria-expanded', mobileMenuToggle.checked ? 'true' : 'false', ); }; menuItems.forEach((item) => { item.addEventListener('click', () => { mobileMenuToggle.checked = false; syncButtonAriaExpanded(); syncMenuAriaHidden(); }); }); mobileMenuToggle.addEventListener('change', () => { syncButtonAriaExpanded(); syncMenuAriaHidden(); }); mobileMenuToggleButton.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); mobileMenuToggle.checked = !mobileMenuToggle.checked; // Programmatic .checked change does not fire 'change'; sync state so menu is focusable when open syncButtonAriaExpanded(); syncMenuAriaHidden(); } }); window.addEventListener('resize', () => { syncMenuAriaHidden(); }); syncMenuAriaHidden(); syncButtonAriaExpanded(); }; document.addEventListener('DOMContentLoaded', mobileMenuHelper);