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