Accessible mega-menu nav walker
A Walker_Nav_Menu subclass that renders disclosure buttons, aria-expanded state and Escape-to-close for dropdown menus.
WordPressNavigationmenuwalkerariaa11y
Code
How it works
What it solves
Hover-only dropdowns lock out keyboard and screen reader users. This walker renders each submenu behind a real button that announces its state, so a mega menu works with touch, mouse and keyboard alike.
How it works
The walker overrides start_lvl to emit a hidden panel list and start_el to print the link plus, for parent items, a sibling button with aria-expanded. A separate button is used rather than hijacking the link, so the parent page stays reachable. The script toggles the panel's hidden attribute, closes it on Escape while returning focus to the button, and closes any open panel when you click elsewhere.
Current items get aria-current="page".
Adapting it
Style .acme-panel as a wide grid for the mega layout and position it under the item. Add the depth class to switch column counts. If you also want hover opening, add it in CSS with :hover only as an enhancement, never as the sole trigger. Set the menu location name in register_nav_menus().
Pitfalls
- Walker method signatures changed in WordPress 5.9; the
$data_objectparameter name is the current one. - Do not forget
end_elandend_lvldefaults; they close the tags, so do not override them carelessly. - Hidden panels are removed from the accessibility tree, which is what you want.
- Test with the keyboard alone before shipping.
How to use it
Save the class in inc/, require it from functions.php, and enqueue assets/mega-menu.js in the footer.
Pass new Acme_Mega_Walker() as the walker argument to wp_nav_menu().
Add CSS so [hidden] panels stay hidden and open ones appear under their parent.
Licence: GPL-2.0-or-later. This snippet comes from WordPress code and is GPL-2.0-or-later.