-
domchocolate
Hi I want to create a barebones theme based on GeneratePress which is totally accessible. The site is at https://barebones.pepped.app/
For this I need the site to be navigable with a keyboard only. To do this I need the following elements to behave in a particular way.
- Pressing tab causes the focus to move to the next focusable element; except
- pressing tab highlights the parent navigational items only and reveals any children/dropdown items
- using an arrow key allows me to scroll through the children/dropdown; otherwise
- tab will jump to the next parent navigational item
- once the navigation is navigated or skipped (using skip to content button) pressing tab will take us to the next focusable element within the body of the page
- and arrow keys simply scroll the page.
My site looks, on first impressions, like this is what’s happening, except the tab and arrow currently both focus on the next focussable element, and the arrows won’t scroll the page.
Does anyone know how I can tweak the theme to do this?
Dominic
-
Fernando
Hi Dominic,
You’ll need Javascript to alter keyboard behaviors. Unfortunately, this would not be within our scope. It would be best to reach out to a developer regarding this. I would suggest asking for recommendations on our Facebook Group as well: https://web.facebook.com/groups/generatepress
-
domchocolate
Hi thanks – I’d argue that the Theme is not accessible as it stands and it should be. It has Javascript that included that renders it inaccessible. As a paid theme and support GP should feel obliged to try and make the product accessible.
-
domchocolate
OK, all – I have sorted this issue independently, and here is the solution. Put this code into your functions.php or use it as a PHP code snippet.
//Navigation-fix function tab_though_menu_skipping_sub_menu_items_unless_down_or_up_arrow_keys_are_used() { ?> <script> document.addEventListener('DOMContentLoaded', function () { const menuItems = document.querySelectorAll('.menu-item-has-children'); // Adjust this selector to match your menu structure // Initially set tabIndex to -1 for all sub-menu items to skip them in tab navigation menuItems.forEach(item => { let subMenuItems = item.querySelectorAll('.sub-menu a'); // Adjust this selector for your sub-menus subMenuItems.forEach(subMenuItem => { subMenuItem.tabIndex = -1; }); item.addEventListener('keydown', function (e) { // Only proceed if the event target is a menu item that contains a sub-menu let subMenu; if (e.target.classList.contains('menu-item-has-children')) { subMenu = e.target.querySelector('.sub-menu'); // Adjust this selector for your sub-menus } else { // This ensures we get the sub-menu even if a child of the menu item was focused subMenu = e.target.closest('.menu-item-has-children').querySelector('.sub-menu'); } let subMenuItems = subMenu.querySelectorAll('a'); // Assumes sub-menu items are anchor tags let focusedElement = document.activeElement; let currentIndex = Array.from(subMenuItems).indexOf(focusedElement); switch(e.key) { case 'ArrowDown': // Move focus to the next sub-menu item if (currentIndex < subMenuItems.length - 1) { subMenuItems[currentIndex + 1].tabIndex = 0; subMenuItems[currentIndex + 1].focus(); e.preventDefault(); // Prevent scrolling the page } else { // Optionally wrap around to the first item subMenuItems[0].tabIndex = 0; subMenuItems[0].focus(); e.preventDefault(); // Prevent scrolling the page } break; case 'ArrowUp': // Move focus to the previous sub-menu item if (currentIndex > 0) { subMenuItems[currentIndex - 1].tabIndex = 0; subMenuItems[currentIndex - 1].focus(); e.preventDefault(); // Prevent scrolling the page } else { // Optionally wrap around to the last item subMenuItems[subMenuItems.length - 1].tabIndex = 0; subMenuItems[subMenuItems.length - 1].focus(); e.preventDefault(); // Prevent scrolling the page } break; } // Reset tabIndex to -1 for items not focused to ensure they're skipped during tab navigation subMenuItems.forEach(subMenuItem => { if (subMenuItem !== document.activeElement) { subMenuItem.tabIndex = -1; } }); }); }); }); </script> <?php } add_action( 'wp_footer', 'tab_though_menu_skipping_sub_menu_items_unless_down_or_up_arrow_keys_are_used', 99 );
-
Hi there,
we take the themes accessibility very seriously so if there is anything we can do to improve it we will definitely do so. So we appreciate your feedback on anything we can do to make things better.
If i understand correctly the issue is; an inability to use Arrow keys to navigate the focused menu.
To the best of my understanding the requirement for Arrow keys is when non-sequential navigation is a requirement:
https://www.w3.org/TR/UNDERSTANDING-WCAG20/navigation-mechanisms-focus-order.html
But not having Arrow keys support, is not a WCAG failure IF, to paraphrase; the Navigation is sequentially and logically ordered and can be navigated using conventional methods eg. keyboard tabbing.
But I will add this Arrow requirement to our development review.
If there is any documentation or other information that may contradict our understanding please let me know. -
domchocolate
BTW you’ll also need this to change the aria-expanded attributes on activation –
document.addEventListener("DOMContentLoaded", function() { var menuItem = document.querySelector(".menu-item-has-children"); var subMenu = menuItem.querySelector(".sub-menu"); var hasMouseEnter = false; var clickedAfterMouseEnter = false; menuItem.addEventListener("mouseenter", function() { this.setAttribute("aria-expanded", "true"); hasMouseEnter = true; }); menuItem.addEventListener("mouseleave", function() { if (!clickedAfterMouseEnter && hasMouseEnter) { this.setAttribute("aria-expanded", "false"); } clickedAfterMouseEnter = false; // Reset the flag }); menuItem.addEventListener("focusin", function() { this.setAttribute("aria-expanded", "true"); hasMouseEnter = true; }); subMenu.addEventListener("transitionend", function(event) { if (event.propertyName === "max-height" && !subMenu.classList.contains("expanded")) { menuItem.setAttribute("aria-expanded", "false"); hasMouseEnter = false; } }); menuItem.addEventListener("click", function(event) { if (!subMenu.classList.contains("expanded")) { this.setAttribute("aria-expanded", "true"); } else { this.setAttribute("aria-expanded", "false"); } clickedAfterMouseEnter = hasMouseEnter; event.preventDefault(); // Prevent default behavior of click event event.stopPropagation(); // Stop propagation to prevent the mouseleave event }); menuItem.addEventListener("focusout", function() { this.setAttribute("aria-expanded", "false"); }); });
-
domchocolate
Thanks – can you let me know if and when this is incorporated into the theme? Then I can update and remove my snippets!
-
It has been raised for review with our development team.
Thanks for sharing your scripts.
- You must be logged in to reply to this topic.