简体   繁体   中英

Keyboard navigation to bootstrap dropdown sub menu

I am converting a dropdown menu to be WCAG compliant and it needs to be navigable by keyboard as well as mouse. As far as I can tell the bootstrap developers have removed sub menu functionality some time ago as it was not mobile friendly. My requirements are desktop only .

I have taken the code from this answer and tried in vain to get it to navigate to the sub menu using the keyboard.

When I update the library to bs4.5 The key navigation on the top-level dropdown is all fine. It even navigates to the first element in the sub menu, but pressing the up and down keys on this menu simply hides the popup.

I've caught the keydown event and blocked the menu from hiding but I have no idea how to move the navigation within the submenu. The code does not appear to be using the active class attribute, as I might have expected.

My requirements are as follows.

  • The sub menu is key navigable by UP/DOWN
  • The sub menu elements can be 'clicked' using the enter key.

Here is what i looks like after pressing enter to activate the sub menu.

在此处输入图像描述

Here is what it looks like when you press the down arrow to move to the sub menu.

在此处输入图像描述

The code (which is pretty much the code from the linked question minus the sub-sub menus)

<html>
    <head>
        <style>
            .dropdown-submenu {
                position: relative;
            }

            .dropdown-submenu a::after {
                transform: rotate(-90deg);
                position: absolute;
                right: 6px;
                top: .8em;
            }

            .dropdown-submenu .dropdown-menu {
                top: 0;
                left: 100%;
                margin-left: .1rem;
                margin-right: .1rem;
            }
        </style>
    </head>
    <body>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
        <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.11.0/umd/popper.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>

        <nav class="navbar navbar-expand-lg navbar-light bg-light">
            <a class="navbar-brand" href="#">Navbar</a>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavDropdown" aria-controls="navbarNavDropdown" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNavDropdown">
                <ul class="navbar-nav">
                    <li class="nav-item active">
                        <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
                    </li>
                    <li class="nav-item dropdown">
                        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                        Dropdown link
                        </a>
                        <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                        <li><a class="dropdown-item" href="#">Action</a></li>
                        <li><a class="dropdown-item" href="#">Another action</a></li>
                        
                        <li class="dropdown-submenu" aria-haspopup="true" aria-expanded="false">
                            <a class="dropdown-item dropdown-toggle" href="#" id="subMenuLink">Submenu</a>
                            <ul class="dropdown-menu">
                                <li><a class="dropdown-item" href="http://www.google.com">Submenu action</a></li>
                                <li><a class="dropdown-item" href="">Another submenu action</a></li>
                            </ul>
                        </li>
                        </ul>
                    </li>
                </ul>
            </div>
        </nav>
    </body>
    <script>        
        $('.dropdown-menu a.dropdown-toggle').on('click', function(e) {
            if (!$(this).next().hasClass('show')) {
                $(this).parents('.dropdown-menu').first().find('.show').removeClass('show');
            }

            var $subMenu = $(this).next('.dropdown-menu');
            $subMenu.toggleClass('show');

            $(this).parents('li.nav-item.dropdown.show').on('hidden.bs.dropdown', function(e) {
                $('.dropdown-submenu .show').removeClass('show');
            });

            return false;
        });         
    </script>
</html>

How can I navigate within the sub menu?

I was able to get the focus caret to move within the sub menu using the following code. This was inspired by looking at the source code for the bootstrap dropdown plugin.

If we attach a keydown handler to the submenus dropdown list, we can get the list of available items in the list as native elements, then get the current index by searching for the target of the key event. Then we can increment or decrement the index as required and set the focus to the new item.

$('.dropdown-submenu .dropdown-menu').on('keydown', function(e) {            

    const items = $(this).find('.dropdown-item').get();
    let index = items.indexOf(event.target)

    if (e.which == 38) {
        index --;
        event.preventDefault()
        event.stopPropagation()
    } else 
    if (e.which == 40) {
        index ++;
        event.preventDefault()
        event.stopPropagation()
    }

    if(index < 0 || index > (items.length - 1)) {
        return
    }

    items[index].focus()
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM