Skip to content

Commit 0fbc4b2

Browse files
committed
PLANET-8026 Trapped focus within mobile nav menu when open
- Updated codebase to trap focus with mobile menu when open
1 parent 9832612 commit 0fbc4b2

File tree

2 files changed

+63
-15
lines changed

2 files changed

+63
-15
lines changed

assets/src/js/header/setupAccessibleNavMenu.js

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ const NAV_DONATE_CLASS = '.nav-donate';
55
const NAV_SUBMENU_CLASS = '.nav-submenu';
66
const SITE_LOGO_CLASS = '.site-logo';
77
const NAV_MENU_CLOSE_CLASS = '.nav-menu-close';
8+
const MOBILE_NAV_ID = '#nav-main';
9+
const PAGE_WRAPPER_ID = '#content';
10+
const NAV_MENU_TOGGLE_CLASS = '.nav-menu-toggle';
811

912
/**
1013
* Function to handle keyboard accessibility in the navigation menu.
@@ -121,6 +124,9 @@ export const setupAccessibleNavMenu = () => {
121124
}
122125

123126
if (mobileNav) {
127+
const doc = mobileNav.ownerDocument;
128+
let lastFocusedElement = null;
129+
const isMobileMenuOpen = () => mobileNav.classList.contains('open');
124130
/**
125131
* Adds event listeners to create a keyboard trap between the buttons.
126132
*/
@@ -156,10 +162,16 @@ export const setupAccessibleNavMenu = () => {
156162
return;
157163
}
158164

159-
hamburgerBtn.addEventListener('keydown', event => {
160-
if (event.key === 'Enter') {
161-
setTimeout(() => logo.focus(), 0);
162-
}
165+
hamburgerBtn.addEventListener('click', () => {
166+
lastFocusedElement = doc.activeElement;
167+
168+
// Wait for CSS class to apply
169+
requestAnimationFrame(() => {
170+
if (isMobileMenuOpen()) {
171+
syncMobileNavAria(true);
172+
logo.focus();
173+
}
174+
});
163175
});
164176
};
165177

@@ -168,21 +180,18 @@ export const setupAccessibleNavMenu = () => {
168180
*/
169181
const focusLogoOnMenuClose = () => {
170182
const closeBtn = mobileNav.querySelector(NAV_MENU_CLOSE_CLASS);
171-
const hamburgerLogo = mobileNav.querySelector(SITE_LOGO_CLASS);
172-
const mainLogo = document.querySelector(`#header ${SITE_LOGO_CLASS}`);
173183

174-
if (!mainLogo || !hamburgerLogo || !closeBtn) {
184+
if (!closeBtn) {
175185
return;
176186
}
177187

178-
closeBtn.addEventListener('keydown', event => {
179-
if (event.key === 'Enter') {
180-
setTimeout(() => mainLogo.focus(), 0);
181-
}
182-
if (event.key === 'Tab' && event.shiftKey) {
183-
setTimeout(() => hamburgerLogo.focus(), 0);
184-
}
188+
closeBtn.addEventListener('click', () => {
189+
requestAnimationFrame(() => {
190+
syncMobileNavAria(false);
191+
lastFocusedElement?.focus();
192+
});
185193
});
194+
186195
};
187196

188197
addKeyboardTrap();
@@ -209,3 +218,36 @@ export const updateNavMenuTabIndex = () => {
209218
];
210219
tabbingItems.forEach(item => item.setAttribute('tabindex', menu.classList.contains('open') ? 0 : -1));
211220
};
221+
222+
/**
223+
* Function to update aria attributes for mobile navigation.
224+
* @param {boolean} isOpen - Whether the mobile navigation is open.
225+
*/
226+
const syncMobileNavAria = isOpen => {
227+
const mobileNav = document.querySelector(MOBILE_NAV_ID);
228+
const page = document.querySelector(PAGE_WRAPPER_ID);
229+
const toggleBtn = document.querySelector(NAV_MENU_TOGGLE_CLASS);
230+
231+
if (!mobileNav || !page || !toggleBtn) {
232+
return;
233+
}
234+
235+
// Mobile menu
236+
if (isOpen) {
237+
mobileNav.removeAttribute('aria-hidden');
238+
} else {
239+
mobileNav.setAttribute('aria-hidden', 'true');
240+
}
241+
242+
// Page behind
243+
if (isOpen) {
244+
page.setAttribute('aria-hidden', 'true');
245+
page.inert = true;
246+
} else {
247+
page.removeAttribute('aria-hidden');
248+
page.inert = false;
249+
}
250+
251+
// Toggle button state
252+
toggleBtn.setAttribute('aria-expanded', String(isOpen));
253+
};

templates/burger-menu.twig

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
<div id="nav-main" class="burger-menu d-lg-none">
1+
<div
2+
id="nav-main"
3+
class="burger-menu d-lg-none"
4+
role="dialog"
5+
aria-modal="true"
6+
aria-label="{{ __( 'Main navigation menu', 'planet4-master-theme' ) }}"
7+
>
28
<div class="burger-menu-header">
39
<a
410
tabindex="-1"

0 commit comments

Comments
 (0)