Viewing 15 posts - 1 through 15 (of 15 total)
  • Author
    Posts
  • #1432379

    Hi, I have a site at https://oxfordwestend.co.uk/. I need the site to be accessible, and I’ve almost completed that. The bit that’s evading me is the dropdown menu in the navigation. Currently, all menu items are accessible by hitting the tab key. This isn’t quite correct – the top level of navigation should be tab-able via the keyboard, but when a dropdown is activated, the menu items should be navigable using the arrow keys (not tab) with a tab only taking you to the next item in the top level and closing any open dropdowns.

    Can someone let me know how I can tweak the theme to allow this to work correctly.

    Thanks in advance

    Dominic

    #1432883

    Hey domchocolate,
    Thank you for your patience and the link to your site, to tab though the menu, skipping sub-menu items unless the down or up arrow keys are used please try this javascript in your child theme functions.php file in Appearance ▸ Editor:

    
    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 );

    I tested this on your site by injecting it in the browser and it worked good with your desktop menu.

    Best regards,
    Mike

    • This reply was modified 9 months, 2 weeks ago by Mike. Reason: updated to correct error
    #1432984

    Thanks, Mike. Appreciate the hard work.

    I’m afraid there’s an error in that code somewhere – when I put it in my dev environment I got a fatal error – “There has been a critical error on this website. Learn more about troubleshooting WordPress.” And –

    An error of type E_PARSE was caused in line 108 of the file /nas/content/live/oxwedev/wp-content/themes/enfold-child/functions.php. Error message: syntax error, unexpected token "-", expecting "(" -

    Line 108 is:

    function tab_though_menu_skipping_sub-menu_items_unless_down_or_up_arrow_keys_are_used() { ?>
    

    And when I try and add it using WP Code snippets I get the same error.

    #1432985

    Hi,

    Thank you for the update.

    The error seems to be generated because of the function name. Please remove the dash or hyphen from the “sub-menu” and replace it with an underscore.

    function tab_though_menu_skipping_sub_menu_items_unless_down_or_up_arrow_keys_are_used() { ?>
    

    Best regards,
    Ismael

    #1432994

    Thanks Ishmael
    But now I just get an error here instead:

    An error of type E_COMPILE_ERROR was caused in line 109 of the file /nas/content/live/oxwedev/wp-content/themes/enfold-child/functions.php. Error message: Cannot redeclare tab_though_menu_skipping_sub_menu_items_unless_down_or_up_arrow_keys_are_used() (previously declared in /nas/content/live/oxwedev/wp-content/plugins/insert-headers-and-footers/includes/class-wpcode-snippet-execute.php(287) : eval()’d code:2)

    #1433015

    OK, I’ve got the code so it no longer shows an error. And I can see the javascript in the page source.

    But it’s not having the desired effect on my site. Any ideas?

    There’s an error around line 1416 – Uncaught SyntaxError: missing ) after argument list – could it be that?

    https://oxwedev.wpengine.com/

    Username and password below

    • This reply was modified 9 months, 2 weeks ago by domchocolate.
    #1433025

    Hi,
    Thanks for the link to your test site, but the standard login url is not working /wp-admin/ so we can’t examine. Please check.

    Best regards,
    Mike

    #1433028

    Sorry that username and password are to get to the frontend only further details below in private content. Thanks again.

    #1433032

    Hi,
    Thanks, I disabled the function in your child theme and added the javascript to your WPCode plugin and found that the console.log code was causing an error:
    console.log(Pressed key: ${e.key});
    so I disabled it as it was only for testing.
    Now the code works, please clear your browser cache and check.

    Best regards,
    Mike

    #1433033

    Hi Mike

    So the code back is now just a javascript snippet and I can delete all the code from the functions.php, is that right? I need to duplicate this on my live server.

    Dominic

    • This reply was modified 9 months, 2 weeks ago by domchocolate.
    #1433037

    Hi,
    Sorry for the confusion, I removed the WPCode snippet and enabled the child theme function again.
    This is the working solution:

    
    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 );

    Best regards,
    Mike

    #1433038

    OK – just to be clear – I can just copy and paste this into my functions on my live site. Is that right?

    Thanks again

    Dominic

    #1433039

    Hi,
    Yes, sorry for the other errors, but you should not have any issues now. Do you see it woking on your test site?

    Best regards,
    Mike

    #1433040

    Yep, it’s working on both sites – thanks so much. This is an excellent fix!

    #1433042

    Hi,
    Glad we were able to help, if you have any further questions please create a new thread and we will gladly try to help you. Thank you for using Enfold.

    Best regards,
    Mike

Viewing 15 posts - 1 through 15 (of 15 total)
  • The topic ‘Dropdown menu accessibility (arrow keys NOT tab)’ is closed to new replies.