Prototab - a lightweight tabbing script based on Prototype.js

This light-weight JavaScript library implements HTML tabs. It does not degrade gracefully, when JavaScript has been disabled. In this case, just the first tab content may be shown, the tab navigation being present, but not functioning.

This script, then, is meant to be used on sites that won't work decently without JavaScript anyway.

Two tab units are shown to prove that the script works with multiple tab units on the same page.

Tested Browsers

Tab Unit 1

This is the 2-line content of Tab 1
another tab 1 line
This is the 1-line content of Tab 2
This is the 3-line content of Tab 3
Line 2 of Tab 3
Line 3 of Tab 3

Tab Unit 2

This is the 2-line content of Tab A
another tab A line
This is the 1-line content of Tab B

The HTML for the first tab unit

< div class="would-be-prototab">
    < ul>
      < li>< a href="#">Tab 1< /a>< /li>
      < li>< a href="#">Tab 2< /a>< /li>
      < li>< a href="#">Tab 3< /a>< /li>
    < /ul>

    < div class="prototab-content">
      < div>This is the 2-line content of Tab 1< br>
            another tab 1 line< /div>
      < div style="display: none">
            This is the 1-line content of Tab 2< /div>
    < /div>
    < div style="display: none">
            This is the 3-line content of Tab 3< br/>
            Line 2 of Tab 3< br/>Line 3 of Tab 3< /div>
< /div>

The Javascript

    /**
       prototab.js - a light-weight tabbing library based on Prototype.js
       @author: Bodo Schulze (bs@cms-schulze.de)
       @date: Sep 3, 2008
       @version: 0.1
       @licence: BSD-like
    */
    (function() {

        var containerClass = 'prototab';
        var activeLiClass  = 'activeLi';

        $$('.'+containerClass).each(function(prototab) {

            // adding a CSS class to the tab container
            // may be used for swapping background images
            prototab.addClassName(containerClass+'-0');

            // get references
            var ul = prototab.down('ul');
            var lis = ul.childElements();
            var content = prototab.down('div');
            var contents = content.childElements();

            // style the (active) first tab
            ul.firstDescendant().addClassName(activeLiClass);

            // helper function to remove all tab-specific CSS classes from
            // the tab container
            removeContainerClasses = function() {
                $R(0, contents.length-1).each(function(id) {
                    prototab.removeClassName(containerClass+'-'+id);
                })
            };

            // the workhorse
            showTab = function(e) {
                // where the event occured
                var a = e.element();

                // update li className
                lis.invoke('removeClassName', activeLiClass);
                var li = a.up('li').addClassName(activeLiClass);

                // the id, yes!
                var id = li.previousSiblings().length;

                // update container class
                removeContainerClasses();
                prototab.addClassName(containerClass+'-'+id);

                // hide/show appropriate DIV
                contents.invoke('hide');
                content.down('div', id).show();

                // stop right here
                e.stop();
            }.bindAsEventListener({});

            ul.childElements().each(function(li) {
                li.down('a').observe('click', showTab);
            });
        });
    })();