Accessible Tab Widget
by jorgeluis
HTML
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<h1>Great Studio Ghibli Movies</h1>
<div id="tabs">
<ul>
<li>
<a href="#totoro">Totoro</a>
</li>
<li>
<a href="#kiki">Kiki’s</a>
</li>
<li>
<a href="#spiritied">Spirited Away</a>
</li>
</ul>
<div>
<h2 id="totoro">My Neighbor Totoro</h2>
<dl>
<dt>Released<dt>
<dd>1988</dd>
<dt>Running time</dt>
<dd>87 minutes</dd>
<dt>Rotten Tomatoes Score</dt>
<dd>
<a href="https://www.rottentomatoes.com/m/my_neighbor_totoro">94%</a>
</dd>
</dl>
</div>
<div>
<h2 id="kiki">Kiki’s Delivery Service</h2>
<dl>
<dt>Released<dt>
<dd>1989</dd>
<dt>Running time</dt>
<dd>102 minutes</dd>
<dt>Rotten Tomatoes Score</dt>
<dd>
<a href="https://www.rottentomatoes.com/m/kikis_delivery_service/">97%</a>
</dd>
</dl>
</div>
<div>
<h2 id="spiritied">Spirited Away</h2>
<dl>
<dt>Released<dt>
<dd>2002</dd>
<dt>Running time</dt>
<dd>124 minutes</dd>
<dt>Rotten Tomatoes Score</dt>
<dd>
<a href="https://www.rottentomatoes.com/m/spirited_away">97%</a>
</dd>
</dl>
</div>
</div>
CSS
/* basic demo styling */
body {
margin: 2em;
color: #444;
line-height: 1.5;
}
h1, h2 {
font-weight: 100;
}
dl {
font-family: sans-serif;
}
/* Tabs module */
#tabs h2 {
margin: 1em 0 0;
}
#tabs h2:focus {
outline: 0;
/* If you're removing the outline, you must add something as good or better! */
text-decoration: underline;
}
.tabsList {
float: left;
list-style: none;
margin: 0;
}
.tabsList li {
position: relative; /*for z-index*/
float: left;
margin: 0 0.5em 0 0;
z-index: 1;
}
.tabsList li a {
position: relative;
float: left;
overflow: hidden;
text-decoration: none;
padding: 0.5em;
background-color: rgba(0, 0, 0, 0.05);
color: #333;
cursor: pointer;
-webkit-transition: background-color 300ms ease-in 100ms;
transition: background-color 300ms ease-in 100ms;
}
.tabsList li a:link {
}
.tabsList li a:hover,
.tabsList li a:focus,
.tabsList li a:active {
background-color: rgba(0, 0, 0, 0.1);
}
.tabsList li a:active {
-webkit-box-shadow: inset 0 5px 4px -5px tomato;
box-shadow: inset 0 5px 1px -3px tomato;
outline: none;
border-color: #FF0000;
}
.tabsList li.current {
z-index: 10;
}
.tabsList li.current a {
background-color: tomato;
color: #fff;
}
.tabsList li.current a:hover,
.tabsList li.current a:focus {
}
.tabsList li.current a:focus {
outline: 1px dotted #444;
}
.tabsList a span {
position: absolute;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
opacity: 0;
}
.tabPanel {
position: relative; /*for z-index*/
display: block;
visibility: visible;
clear: left;
overflow: auto;
padding: .5em 3em 2em;
z-index: 5;
border-top: solid 1px #ddd;
}
.tabPanel:focus { outline: 1px dotted #999; }
.tabPanel h2 { display: inline-block; }
.tabPanel h2:focus { outline: 1px dotted #999; }
JavaScript
$(function () {
var tabs = $("#tabs");
// For each individual tab DIV, set class and aria-hidden attribute, and hide it
$(tabs).find("> div").attr({
"class": "tabPanel",
"aria-hidden": "true"
}).hide();
// Get the list of tab links
var tabsList = tabs.find("ul:first").attr({
"class": "tabsList",
});
// For each item in the tabs list...
$(tabsList).find("li > a").each(
function (a) {
var tab = $(this);
// Create a unique id using the tab link's href
var tabId = "tab-" + tab.attr("href").slice(1);
// Assign tab id and aria-selected attribute to the tab control, but do not remove the href
tab.attr({
"id": tabId,
"aria-selected": "false",
}).parent().attr("role", "presentation");
// Assign aria attribute to the relevant tab panel
$(tabs).find(".tabPanel").eq(a).attr("aria-labelledby", tabId);
// Set the click event for each tab link
tab.click(
function (e) {
var tabPanel;
// Prevent default click event
e.preventDefault();
// Change state of previously selected tabList item
$(tabsList).find("> li.current").removeClass("current").find("> a").attr("aria-selected", "false");
// Hide previously selected tabPanel
$(tabs).find(".tabPanel:visible").attr("aria-hidden", "true").hide();
// Show newly selected tabPanel
tabPanel = $(tabs).find(".tabPanel").eq(tab.parent().index());
tabPanel.attr("aria-hidden", "false").show();
// Set state of newly selected tab list item
tab.attr("aria-selected", "true").parent().addClass("current");
// Set focus to the first heading in the newly revealed tab content
tabPanel.children("h2").attr("tabindex", -1).focus();
}
);
}
);
// Set keydown events on tabList item for navigating tabs
$(tabsList).delegate("a", "keydown",
function (e) {
var tab = $(this);
switch (e.which) {
case 37: case 38:
if (tab.parent().prev().length != 0) {
tab.parent().prev().find(">...