Last active
March 7, 2016 10:33
-
-
Save esthezia/5804731 to your computer and use it in GitHub Desktop.
Accessible Tabs (jQuery) - Minimal setup
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en" class="nojs"> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" /> | |
<title>jQuery - Accessible Tabs</title> | |
<meta name="description" content="" /> | |
<meta name="viewport" content="width=device-width, minimum-scale=1" /> | |
<meta name="format-detection" content="telephone=no" /> | |
<meta name="format-detection" content="address=no" /> | |
<meta http-equiv="cleartype" content="on" /> | |
<script>document.documentElement.className = "";</script> | |
<style> | |
a:focus { outline: thin dotted; } | |
.js-tabpanel { display: none; } | |
.is-tabpanel-selected { display: block; } | |
</style> | |
</head> | |
<body> | |
<!--[if lt IE 7]> | |
<p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p> | |
<![endif]--> | |
<div class="js-tabs" id="tabs"> | |
<div class="js-tablist" role="tablist"> | |
<a href="?tab=1#tabs" class="js-tab is-tab-selected" id="tab-1" role="tab" aria-selected="true" aria-controls="tabpanel-1">Tab 1</a> | |
<a href="?tab=2#tabs" class="js-tab" id="tab-2" role="tab" aria-selected="false" aria-controls="tabpanel-2">Tab 2</a> | |
<a href="?tab=3#tabs" class="js-tab" id="tab-3" role="tab" aria-selected="false" aria-controls="tabpanel-3">Tab 3</a> | |
</div> | |
<div class="js-tabpanel is-tabpanel-selected" id="tabpanel-1" role="tabpanel" aria-labelledby="tab-1" aria-hidden="false"> | |
Tabpanel 1 | |
</div> | |
<div class="js-tabpanel" id="tabpanel-2" role="tabpanel" aria-labelledby="tab-2" aria-hidden="true"> | |
Tabpanel 2 | |
</div> | |
<div class="js-tabpanel" id="tabpanel-3" role="tabpanel" aria-labelledby="tab-3" aria-hidden="true"> | |
Tabpanel 3 | |
</div> | |
</div> | |
<script src="http://code.jquery.com/jquery-latest.min.js"></script> | |
<script> | |
var a = a || {}; | |
a.jQuery = jQuery.noConflict(true); | |
a.jQuery(function ($) { | |
a.keys = { | |
"up": 38, | |
"down": 40, | |
"left": 37, | |
"right": 39, | |
"tab": 9, | |
"pageup": 33, | |
"pagedown": 34, | |
"end": 35, | |
"home": 36, | |
"enter": 13, | |
"backspace": 8, | |
"delete": 46, | |
"f5": 116 | |
}; | |
a.aKeys = []; | |
for (var k in a.keys) { | |
a.aKeys.push(a.keys[k]); | |
} | |
a.tabs = function (i, el) { | |
$(".js-tabs").each(function () { | |
var t = $(this), | |
nav = t.find(".js-tablist:first"), | |
panels = t.find(".js-tabpanel"), | |
navOnClass = "is-tab-selected", | |
panelOnClass = "is-tabpanel-selected", | |
navOn = nav.children("." + navOnClass), | |
panelOn; | |
// support tabs within tabs. | |
// remove tabpanels that don't belong to the current tabs container's functionality. | |
panels.each(function () { | |
if (!$(this).closest(".js-tabs").is(t)) { | |
panels = panels.not($(this)); | |
} | |
}); | |
panelOn = panels.filter("." + panelOnClass); | |
function selectTab () { | |
var tab = $(this), | |
i; | |
if (tab.hasClass(navOnClass)) { | |
return false; | |
} | |
navOn.removeClass(navOnClass); | |
navOn = tab; | |
i = navOn.index(); | |
navOn.addClass(navOnClass); | |
panelOn.removeClass(panelOnClass).attr("aria-hidden", "true"); | |
panelOn = panels.filter(":eq(" + i + ")"); | |
panelOn.addClass(panelOnClass).attr("aria-hidden", "false"); | |
return false; | |
} | |
// not using "focus" because it will also get triggered when the browser window gets focused, | |
// and this could negatively impact the behaviour. | |
// e.g. when tracking clicks on tabs (event tracking with Google Analytics) | |
nav.children().click(selectTab).keydown(function (e) { | |
var tab = $(this), | |
key = e.keyCode || e.which, | |
keys = a.keys, | |
nextA = tab.next(), | |
prevA = tab.prev(), | |
firstA = nav.children(":eq(0)"), | |
lastA = nav.children(":last"), | |
// ctrl = e.ctrlKey && !e.shiftKey && !e.altKey, | |
shift = e.shiftKey; | |
nextA = nextA.length === 1 ? nextA : nav.children(":first"); | |
prevA = prevA.length === 1 ? prevA : nav.children(":last"); | |
if (key === keys.home) { | |
firstA.triggerHandler("click"); | |
firstA.get(0).focus(); | |
return false; | |
} | |
if (key === keys.end) { | |
lastA.triggerHandler("click"); | |
lastA.get(0).focus(); | |
return false; | |
} | |
if ((key === keys.right) || (key === keys.down)) { | |
if (!nextA) { return true; } | |
nextA.triggerHandler("click"); | |
nextA.get(0).focus(); | |
return false; | |
} | |
if ((key === keys.left) || (key === keys.up)) { | |
if (!prevA) { return true; } | |
prevA.triggerHandler("click"); | |
prevA.get(0).focus(); | |
return false; | |
} | |
if ((key === keys.tab) && !shift) { | |
if (panelOn.find("input, a, select").first().length) { | |
panelOn.find("input, a, select").first().get(0).focus(); | |
} | |
// return true because we don't want to block navigating by pressing the "tab" key | |
return true; | |
} | |
}); | |
}); | |
}; | |
a.tabs(); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment