Dropdown
An Accessibility-enabled dropdown list with custom checkmarks
by Kyle Falconer
HTML
<div>something before</div>
<div>
<div class="filterGroup" onclick="toggleFilterGroup(this)">
<div role="button" aria-pressed="false" aria-haspopup="true">Role<span class="indicator_triangle"></span>
</div>
<ul aria-expanded="false">
<li role="checkbox" data-name="PrimaryRole" data-value="Faculty">Faculty</li>
<li role="checkbox" data-name="PrimaryRole" data-value="Staff">Staff</li>
<li role="checkbox" data-name="PrimaryRole" data-value="Student">Student</li>
</ul>
</div>
<div class="filterGroup" onclick="toggleFilterGroup(this)">
<div role="button" aria-haspopup="true">Department<span class="indicator_triangle"></span>
</div>
<ul aria-expanded="false">
<li role="checkbox" data-name="PrimaryRole" data-value="Admissions">Admissions</li>
<li role="checkbox" data-name="PrimaryRole" data-value="Computer Science">Computer Science</li>
<li role="checkbox" data-name="PrimaryRole" data-value="Relations">Relations</li>
</ul>
</div>
</div>
<div>something after</div>
CSS
div {
display:block;
min-height:50px;
}
/*
div::after {
content:' ';
display:block;
height:0;
width:0;
clear:both;
float:none;
}*/
#SearchFilterWrapper {
overflow: visible;
}
#SearchFilterWrapper.grid_whole {
margin-bottom: 0;
}
.filterGroup {
float:left;
}
.filterGroup *[role="button"] {
display:inline-block;
min-height: 25px;
min-width:40px;
cursor: pointer;
overflow:hidden;
color:#80151a;
margin-right: 120px;
}
.filterGroup ul {
height:0;
margin:0;
padding: 0;
border:none;
position:absolute;
z-index: 200;
transition:height 1s, border 1s, padding 1s;
-webkit-transition:height 0.4s, border 0.4s, padding 0.4s;
overflow:hidden;
list-style:none;
background-color:#ffffff;
-webkit-box-shadow: 4px 4px 7px -2px rgba(0, 0, 0, 0.75);
-moz-box-shadow: 4px 4px 7px -2px rgba(0, 0, 0, 0.75);
box-shadow: 4px 4px 7px -2px rgba(0, 0, 0, 0.75);
}
.filterGroup.Open ul {
height:100px;
padding: 0;
border: 1px solid #cfcfcf;
}
.indicator_triangle {
display:inline-block;
width: 0px;
height: 0px;
border-style: solid;
border-width: 0 5px 8.7px 5px;
border-color: #80151a transparent #80151a transparent;
-webkit-transform:rotate(360deg);
border-style: solid;
margin-left: 10px;
}
.Open .indicator_triangle {
border-width: 8.7px 5px 0 5px;
}
.filterGroup li[role="checkbox"] {
display:block;
margin:0;
padding:4px 10px 4px 4px;
cursor: pointer;
}
.filterGroup li[role="checkbox"]:hover {
background-color:#efefef;
}
.filterGroup li[role="checkbox"]:before {
display:inline-block;
margin-right:5px;
width:15px;
}
.filterGroup li[aria-checked="false"]:before {
content:' ';
}
.filterGroup li[aria-checked="true"]:before {
content:'\2713';
}
JavaScript
var Utils = Utils || {};
/**
* A more compatible way of attaching event listeners.
* Works on IE 7+
* Note that if Element.prototype.addEventListener is not supported,
* useCapture will be ignored.
* @see http://stackoverflow.com/a/12949687/940217
* @param {Element} ele
* @param {string} type
* @param {function(?)} handler
* @param {boolean=} useCapture
* @return {undefined}
*/
Utils.addEventListener = function (ele, type, handler, useCapture) {
useCapture = useCapture || false;
if (ele.addEventListener) {
ele.addEventListener(type, handler, useCapture);
} else if (ele.attachEvent) {
ele.attachEvent("on" + type, handler);
} else {
ele["on" + type] = handler;
}
};
/**
* A more compatible way of removing event listeners.
* Works on IE 7+.
* Note that if Element.prototype.removeEventListener is not supported,
* useCapture will be ignored.
* @see http://stackoverflow.com/a/12949687/940217
* @param {Element} ele
* @param {string} type
* @param {function(?)} handler
* @param {boolean=} useCapture
* @return {undefined}
*/
Utils.removeEventListener = function (ele, type, handler, useCapture) {
useCapture = useCapture || false;
if (ele.removeEventListener) {
ele.removeEventListener(type, handler, useCapture);
} else if (ele.detachEvent) {
ele.detachEvent("on" + type, handler);
} else {
ele["on" + type] = null;
}
};
var isOpenRegex = /(^|\s)Open(\s|$)/;
/** @param {Element} elem */
window['toggleFilterGroup'] = function (elem) {
var closeFilterGroup = function () {
setTimeout(function () {
window.console && window.console.log('closing filter group near element: ', elem);
Utils.removeEventListener(document.body, 'click', closeFilterGroup, false);
Utils.removeEventListener(elem, 'click', closeFilterGroup, false);
elem.getElementsByTagName('ul')[0].setAttribute('aria-expanded', 'false');
...