Accordion (Multiselect)

Accordion (Multiselect)

Turn on a screen reader to experience this example in action.

HTML Source Code

<div class="accordion" role="navigation">
    <ul id="mainnav" role="menu">
        <li class="level1 parent" role="menuitem" >
            <span tabindex="0" role="button" id="prospectHeader" class="category">Prospective Students</span>
            <ul class="accordionSubMenu"  role="menu" aria-labelledby="prospectHeader">
                <li class="first level2" role="presentation"><a href="#" role="menuitem" >Prospective Students Home Page</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Admissions</a></li>
                <li class="last level2" role="presentation"><a href="#" role="menuitem">Financing Your Education</a></li>
            </ul>
        </li>
        <li class="level1 parent" role="menuitem">
            <span role="button" id="studentHeader" class="category" tabindex="0">Students</span>
            <ul class="accordionSubMenu"  role="menu" aria-labelledby="studentHeader">
                <li class="first level2" role="presentation"><a href="#" role="menuitem">Students Home Page</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Records</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Student Life</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Student Organizations</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Technology</a></li>
                <li class="last level2" role="presentation"><a href="#" role="menuitem">Library</a></li>
            </ul>
        </li>
        <li class="level1 parent" role="menuitem">
            <span role="button" id="facultyHeader" class="category" tabindex="0">Faculty</span>
            <ul class="accordionSubMenu"  role="menu" aria-labelledby="facultyHeader">
                <li class="first level2" role="presentation"><a href="#" role="menuitem">Faculty Home</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Directory</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">News</a></li>
                <li class="last level2" role="presentation"><a href="#" role="menuitem">Publications</a></li>
            </ul>
        </li>
        <li class="level1 parent" role="menuitem">
            <span role="button" id="alumniHeader" class="category" tabindex="0">Alumni</span>
            <ul class="accordionSubMenu"  role="menu" aria-labelledby="alumniHeader">
                <li class="first level2" role="presentation"><a href="#" role="menuitem">Alumni Home Page</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Benefits and Services</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Giving</a></li>
                <li class="level2" role="presentation"><a href="#" role="menuitem">Alumni Association</a></li>
                <li class="last level2" role="presentation"><a href="#" role="menuitem">Volunteer Opportunities</a></li>
            </ul>
        </li>
    </ul>
</div>

JavaScript Source Code

Dependencies:

  • JQuery
var iOS = (navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false);
var titleAttr = (iOS) ? 'title' : 'data-title';
var initNavMenu = function () {
    //add keyboard/mouse handler to top level items; add kbd handler to children

    $('#mainnav > li').keydown(menuTopKeyPress);
    $('#mainnav ul li').keydown(menuChildKeyPress);
    $('#mainnav > li > span').click(menuTopClick);
    //add ARIA tags
    //
    //aria-haspopup="true"
    //aria-controls="id_of_subnav"
    //aria-expanded="false" (changes to true when sub-nav is visible)

    $('#mainnav > li').has('ul').children("span").attr("aria-expanded", "false")
        .attr(titleAttr, 'click to display');


    //ARIA tags for the submenu
    //
    //role="group"
    //aria-expanded="false" (changes to true when sub-nav is visible)
    //aria-labelledby="id_of_top_level_link"

    $('#mainnav > li ul').attr("aria-expanded", "false");
    //.attr("role", "group");
};

var menuTopClick = function (event) {
    var subMenu = $(event.currentTarget).parent().find("ul");
    if (!subMenu.hasClass("expanded")) {
        expandMenu(subMenu);
    } else {
        collapseMenu(subMenu);
    }
    event.preventDefault();
};

var menuTopKeyPress = function (event) {
    var subMenu = $(event.currentTarget).find("ul");
    if (event.which === 13 || event.which === 32) { //enter key
        if (!subMenu.hasClass("expanded")) {
            expandMenu(subMenu);
        } else {
            collapseMenu(subMenu);
        }
    } else if (event.which === 37) { //left arrow key
        //if there's a previous one, go to that; otherwise nothing
        var prevItem = $(event.currentTarget).prev("li").children("span");
        if (prevItem.length > 0) {
            prevItem.focus();
        };
    } else if (event.which === 39 || event.which === 40) { //right arrow key
        //if there's a next one, go to that; otherwise nothing
        var nextItem = $(event.currentTarget).next("li").children("span");
        if (nextItem.length > 0) {
            nextItem.focus();
        };
    } else if (event.which === 38) { //up arrow
        var prevItem = $(event.currentTarget).prev("li");
        if (prevItem.length > 0) {
            if (prevItem.children("ul").hasClass("expanded")) {
                prevItem.find("ul li").last().children("a").focus();
            } else {
                prevItem.children("span").focus();
            }
        }
        event.preventDefault();
    } else if (event.which === 27) { // esc
        //close the menu
        if (subMenu.hasClass("expanded")) {
            collapseMenu(subMenu);
        }
        event.preventDefault();
    }
};


var menuChildKeyPress = function (event) {
    if (event.which === 13 || event.which === 32) { //enter key or space key
        event.stopPropagation();
    } else if (event.which === 40) { //down arrow
        //go to the next item if there is one; otherwise go to next menu if there is one
        var nextItem = $(event.currentTarget).next("li");
        if (nextItem.length > 0) {
            nextItem.children("a").focus();
        } else {
            var nextMenu = $(event.currentTarget).parent().parent().next("li");
            if (nextMenu.length > 0) {
                nextMenu.children("span").focus();
            }
        }
        event.stopPropagation();
        event.preventDefault();
    } else if (event.which === 38) { //up arrow
        //go to prev item if there is one; otherwise, go up to the parent menu
        var prevItem = $(event.currentTarget).prev("li");
        if (prevItem.length > 0) {
            prevItem.children("a").focus();
        } else {
            $(event.currentTarget).parent().closest("li").children("span").focus();
        }
        event.stopPropagation();
        event.preventDefault();
    }
};


var expandMenu = function (menu) {
    menu.toggleClass("expanded", true);
    menu.attr("aria-expanded", "true");
    menu.parent().closest("li").addClass("here");
    menu.parent().closest("li").children("span").attr(titleAttr, "select to hide").attr("aria-expanded", "true").focus();
    menu.parent().closest("li").children("ul").show();
};

var collapseMenu = function (menu) {
    //Close the menu, and if focus was inside it, put focus on the menu itself
    var focusedChild = menu.find(":focus");
    if (focusedChild.length > 0) {
        menu.parent().children("span").focus();
    }
    menu.parent().removeClass("here");
    menu.parent().children("span").attr("aria-expanded", "false").attr(titleAttr, "select to display");
    menu.toggleClass("expanded", false).attr("aria-expanded", "false");
    menu.parent().children("ul").hide();
};

$(document).ready(initNavMenu);

CSS Source Code

.accordion ul {
    font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;
    list-style:none;
    margin:0;
    padding:0;
    /* width:300px; */
    width: auto;
    max-width: 300px;
    word-break: break-word;
    overflow-wrap: break-word;
}
.accordion ul.accordionSubMenu {
    display:none;
}
.accordion ul .here ul {
    display:block;
}
.accordion li {
    list-style:none;
    margin:0;
    padding:0;
}
.accordion li .category {
    background:#375898;
    border:1px solid #fff;
    color:#fff;
    display:block;
    padding:3px 6px;
}
.accordion li li {
    background:#fff;
    color:#375898;
}
.accordion li a {
    border-bottom:1px dashed #375898;
    color:#375898;
    display:block;
    padding:3px 5px 3px 20px;
    text-decoration:none; 
}
.accordion li.last a {
    border-bottom:none;
}
.accordion li .category:hover {
    background:#4b6fb6;
    color: #FFC;
    cursor:pointer;
}
.accordion li a:hover {
    background:#ffc;
    cursor:pointer;
}
.expanded {
    display: block;
}
.accordion li.self a {
    background:#FFC;
    color:#990000;
}

Copy and Paste Full Page Example