Skip to content

Commit b091e9c

Browse files
committed
Significantly better ARIA keyboard support
1 parent 7e1e2d5 commit b091e9c

File tree

3 files changed

+163
-17
lines changed

3 files changed

+163
-17
lines changed

dist/jquery.slicknav.js

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@
3535
mobileMenu = 'slicknav',
3636
prefix = 'slicknav';
3737

38+
Keyboard = {
39+
DOWN: 40,
40+
ENTER: 13,
41+
ESCAPE: 27,
42+
LEFT: 37,
43+
RIGHT: 39,
44+
SPACE: 32,
45+
TAB: 9,
46+
UP: 38,
47+
};
48+
3849
function Plugin(element, options) {
3950
this.element = element;
4051

@@ -112,7 +123,7 @@
112123
$(menuBar).append(brand);
113124
}
114125
$this.btn = $(
115-
['<' + settings.parentTag + ' aria-haspopup="true" tabindex="0" class="' + prefix + '_btn ' + prefix + '_collapsed">',
126+
['<' + settings.parentTag + ' aria-haspopup="true" role="button" tabindex="0" class="' + prefix + '_btn ' + prefix + '_collapsed">',
116127
'<span class="' + prefix + '_menutxt">' + settings.label + '</span>',
117128
'<span class="' + iconClass + '">',
118129
'<span class="' + prefix + '_icon-bar"></span>',
@@ -251,20 +262,82 @@
251262
$this._itemClick($(this));
252263
});
253264

254-
// check for enter key on menu button and menu parents
265+
// check for keyboard events on menu button and menu parents
255266
$($this.btn).keydown(function (e) {
256267
var ev = e || event;
257-
if(ev.keyCode == 13) {
258-
e.preventDefault();
259-
$this._menuToggle();
268+
269+
switch(ev.keyCode) {
270+
case Keyboard.ENTER:
271+
case Keyboard.SPACE:
272+
case Keyboard.DOWN:
273+
e.preventDefault();
274+
if (ev.keyCode !== Keyboard.DOWN || !$($this.btn).hasClass(prefix+'_open')){
275+
$this._menuToggle();
276+
}
277+
278+
$($this.btn).next().find('[role="menuitem"]').first().focus();
279+
break;
260280
}
281+
282+
261283
});
262284

263285
$this.mobileNav.on('keydown', '.'+prefix+'_item', function(e) {
264286
var ev = e || event;
265-
if(ev.keyCode == 13) {
266-
e.preventDefault();
267-
$this._itemClick($(e.target));
287+
288+
switch(ev.keyCode) {
289+
case Keyboard.ENTER:
290+
e.preventDefault();
291+
$this._itemClick($(e.target));
292+
break;
293+
case Keyboard.RIGHT:
294+
e.preventDefault();
295+
if ($(e.target).parent().hasClass(prefix+'_collapsed')) {
296+
$this._itemClick($(e.target));
297+
}
298+
$(e.target).next().find('[role="menuitem"]').first().focus();
299+
break;
300+
}
301+
});
302+
303+
$this.mobileNav.on('keydown', '[role="menuitem"]', function(e) {
304+
var ev = e || event;
305+
306+
switch(ev.keyCode){
307+
case Keyboard.DOWN:
308+
e.preventDefault();
309+
var allItems = $(e.target).parent().parent().children().children('[role="menuitem"]:visible');
310+
var idx = allItems.index( e.target );
311+
var nextIdx = idx + 1;
312+
if (allItems.length <= nextIdx) {
313+
nextIdx = 0;
314+
}
315+
var next = allItems.eq( nextIdx );
316+
next.focus();
317+
break;
318+
case Keyboard.UP:
319+
e.preventDefault();
320+
var allItems = $(e.target).parent().parent().children().children('[role="menuitem"]:visible');
321+
var idx = allItems.index( e.target );
322+
var next = allItems.eq( idx - 1 );
323+
next.focus();
324+
break;
325+
case Keyboard.LEFT:
326+
e.preventDefault();
327+
if ($(e.target).parent().parent().parent().hasClass(prefix+'_open')) {
328+
var parent = $(e.target).parent().parent().prev();
329+
parent.focus();
330+
$this._itemClick(parent);
331+
} else if ($(e.target).parent().parent().hasClass(prefix+'_nav')){
332+
$this._menuToggle();
333+
$($this.btn).focus();
334+
}
335+
break;
336+
case Keyboard.ESCAPE:
337+
e.preventDefault();
338+
$this._menuToggle();
339+
$($this.btn).focus();
340+
break;
268341
}
269342
});
270343

dist/jquery.slicknav.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)