Accessible Tab Navigation (version 4)
author: mike foskett incept: 21st May 2010
last update: 31st January 2012
A progressively enhanced lightweight and accessible tab navigation which doesn't rely on jQuery.
Written to replace a jQuery method which wasn't accessible via the keyboard and didn't work without JavaScript. Originally written for the Tesco direct web site.
Version 4 updated to include multiple versions on one page and to allow hover, or focus, action to activate tabs.
Example
Tab One
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed tristique volutpat est, fermentum posuere ligula pretium egestas. Cras id justo nibh, at laoreet nisi. Quisque accumsan faucibus malesuada.
Tab Two
Pellentesque ut sem sapien. Integer vitae dui elit, eu interdum erat. Duis non velit sed leo convallis imperdiet. Etiam ullamcorper imperdiet nisi eu interdum. Phasellus accumsan laoreet accumsan.
Tab Three
Ut suscipit ultrices commodo. Aliquam erat volutpat. Aliquam erat volutpat. Aenean sed odio augue. Cras pellentesque accumsan ipsum, at molestie dolor malesuada laoreet. Suspendisse nec pharetra orci.
A complete commented bare bones demo version is available. As is a minified JavaScript [1.05 KB] version.
Caveat: This code will only produce a single tab navigation an a page. If you require more than one it means duplicating the JavaScript and changing the id's. Not the best solution but works. Live example with two separate tab navigations: Tesco mini-site for AMD. I may further this project to correctly accommodate multiples in the future. - Done in version 4.
The XHTML
Basically a list of anchor links which reference div blocks.
<ul id="tabableNav" class="hoverable">
<li class="on"><a href="#tab1">Tab One</a></li>
<li><a href="#tab2">Tab Two</a></li>
<li><a href="#tab3">Tab Three</a></li>
</ul>
The class="on" distinguishes which tab is currently active.
<div>
<div id="tab1" class="tabbed on">
tab 1 content
</div>
<div id="tab2" class="tabbed">
tab 2 content
</div>
<div id="tab3" class="tabbed">
tab 3 content
</div>
</div>
The class="tabbed" hides inactive tab blocks when JavaScript is present.
The class="on" displays which tab is currently active.
The scripting
The script is presented in a closure to prevent variables interfering elsewhere. It was also Linted as far as possible.
var accessibleTabs4 = (function () {
var onClass;
// author: Simon Willisons - http://simonwillison.net/2004/May/26/addLoadEvent/
function addLoadEvent(f){var o=window.onload;if(typeof window.onload!=='function'){window.onload=f;}else{window.onload=function(){if(o){o();}f();};}}
// A few of my standard set of functions
function hasClass(o,c){return new RegExp('(\\s|^)'+c+'(\\s|$)').test(o.className);}
function addClass(o,c){if(!hasClass(o,c)){o.className+=' '+c;}}
function removeClass(o,c){if(hasClass(o,c)){o.className=o.className.replace(new RegExp('(\\s|^)'+c+'(\\s|$)'),' ').replace(/\s+/g,' ').replace(/^\s|\s$/,'');}}
The activateTab function is called whenever a tab is clicked, or optionally hovered / focused.
function activateTab() {
var j = this.linkset.length; // number of links in this tab set
while (j--) { // go through each link in turn
// remove the "on" class from both link and content div
removeClass(this.linkset[j].parentNode, onClass);
removeClass(this.linkset[j].tabId, onClass);
}
// Add the "on" class to both the active link and content div
addClass(this.parentNode, onClass);
addClass(this.tabId, onClass);
return false;
}
Initialisation waits until the page has loaded. Then works through each tab link and associates
function init(cfg) {
addLoadEvent(function () { // wait until page has fully loaded
var tabNavId = document.getElementById(cfg.navId); // get the ul id from the function parameter
onClass = cfg.onClass || "on"; // On class defaults to "on" but may be overwritten by a function parameter
if (tabNavId) { // if id passed as a parameter exists
var As = tabNavId.getElementsByTagName("a"), // get list of contained links as objects
i = As.length,
hoverable = hasClass(tabNavId, cfg.hoverableClass || "hoverable"); // check if hover / focus action is required
while (i--) { // now with each link object
As[i].tabId = document.getElementById(As[i].href.slice(As[i].href.lastIndexOf('#') + 1)) || false; // get the content id from the href or false if not available
if (As[i].tabId) {
As[i].linkset = As; // each link object stores a reference to each link in the list
// add the action to each link
As[i].onclick = activateTab;
if (hoverable) {
As[i].onmouseover = activateTab;
As[i].onfocus = activateTab;
}
}
}
}
});
}
return {init : init};
}());
// Call the function with the id of navigation tab ul as a parameter
// Optionally overwrite the default settings:
// onClass : "on", hoverableClass : "hoverable"
accessibleTabs4.init({navId : "tabableNav"});
The CSS
The styling requires JavaScript detection so it can act prior to page rendering. Indicated by the class "hasJS" added to the html element. This is achieved by adding a small script directly after the title element:
<script type="text/javascript">/*<![CDATA[*/document.documentElement.className="hasJS";/*]]>*/</script>
Styling required by the scripting only. Nothing cosmetic here:
.hasJS .tabbed {position:absolute; top:0; left:-200em;}
.hasJS .on {position:relative; top:0; left:0}
Any issues please email me or leave a comment below.
Have your say…
The commenting system used here is a modified version of comment_rave. Capcha method by Hardcode NL.
