Listbox and keyboard navigation


For this article, we start from the example of the listbox with checkboxes. The objective is to improve keyboard navigation in order to get close to the W3C / WAI guidelines.

ARIA patterns

The W3C maintains online specifications that describe how ARIA components should behave: WAI-ARIA Authoring Practices 1.1.

The specifications for the listbox tell us that:



The functionality to automatically select the item by typing the first letters is not easy to implement. The following example uses XPath.

The first thing to do is listen to the keyboard once the focus is on the list. Depending on the key, it performs an action (selecting an item, moving the selected item…).

    // On keydown
    $("[role=listbox]").on("keydown", function (e) {            
        var currentItem = $(this).find("[aria-selected=true]");                      
        switch (e.keyCode) {
            case 9: // TAB
            case 36: // home                    
            case 35: // end
            case 38:  // Up arrow

Other keys that are not used to perform an action on the list, i.e. letters and digits, are saved to create the search string. When the user does not type anything for a few milliseconds (500 in our example), we look for a list item that begins with the typed string and select it.

    case 65: // Ctrl + A
        if (e.ctrlKey) {
    default:  // Search item starts with  
        // Cancel current timer                                                                  

        // Create search string
        searchString += e.key;
        var self = this;

        // Set a timer to search item after 500ms
        timer = setTimeout(function(){
            // Search item
            var xpath = "li/span[starts-with(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), '" + searchString + "')]";
            var matchingElement = document.evaluate(xpath, self, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;

            // Reset search string
            searchString = "";

            // If an item is found…
            if (matchingElement) {                            
                currentItem.attr("aria-selected", "false");
                $(matchingElement).parent().attr("aria-selected", "true").focus().addClass("active");
        }, 500);           


To search the item in the list, we use the following XPath query /li/span[starts-with(text(), "the string to search")]. In addition, in order to fix the character case issue, we use the translate function.

Finally, for compatibility issues with Internet Explorer, we use the Google XPath polyfill, you just need to include it and install it at page load using: wgxpath.install();.