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(">...