Tabs How To

This component allows you to create a tab system which can be used in three different ways:

  • With all the structure and content already on the page, using the JS only for behavior and degrading in the lack of javascript
  • With the HTML menu present on the page and adding the content dynamically with JS (AJAX, callback or a simple content string).
  • Create the tab system programatically for later addition to the html (useful for more complex JavaScript? modules).

Demo

 http://js.sapo.pt/SAPO/Component/Tabs/sample/



Initial configuration

To use this component you need the following files:

<script type="text/javascript" src="http://js.sapo.pt/SAPO/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Dom/Loaded/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Dom/Css/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Dom/Event/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Dom/Element/0.1/"></script
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Utility/Url/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Utility/Dimensions/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Communication/Ajax/0.1/"></script>
<script type="text/javascript" src="http://js.sapo.pt/SAPO/Component/Tabs/0.1/"></script>

Important notes

Each tab container has a sapo-tabs-container class and the currently visible tab has a sapo-active-container. These classes definition is automatically injected in the page, but this css can be extended.

The tabs menu gets a class sapo-tabs-nav and the currently active item in this menu gets a class sapo-active-nav.

The names of these classes are all configurable through the initialization options but on the modes where you need HTML on the page the existence of these classes is mandatory.

After the following mode listing there's an explanation of all the other possible parameters for applying behaviors to tabs and also some other options.

Only the first mode is progressively enhanced, so that it's still usable if JavaScript? is deactivated. Besides that, this mode also allows the use of anchor links to access a given tab, supporting various levels of nested tabs. Example:  http://js.host/SAPO/Component/Tabs/sample/#description2 or  http://js.host/SAPO/Component/Tabs/sample/#/news/description2 The second type of links only works when javascript is available.



First mode - Add behavior to HTML present on the page

This mode expects the user to have HTML present on the page and adds the tab behavior to this HTML structure. For this to happen, the HTML needs to have the following structure, including CSS classes:

<div id="tabSet">
    <ul class="sapo-tabs-nav">
        <li><a href="#firstTabName">first tab name</a></li>
        <li><a href="#secondTabName">second tab name</a></li>
    </ul>
    
    <div id="firstTabName" class="sapo-tabs-container">
        first tab content
    </div>

    <div id="secondTabName" class="sapo-tabs-container">
        second tab content
    </div>
</div>

The classes specified here are mandatory for the behavior to work.

Optionally, and only in this first mode, you can add a sapo-tabs-nojs class on the top level container of the tab system, so you can have a different style in case the JavaScript? is deactivated. When you use the tabs module, the JavaScript? code removes this class, if it exists.

Now you only need to apply the JavaScript? behavior. To do that, you need the following code, inside a DOM ready or DOM loaded event:

SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs("tabSet");
});

This is the most simple case in which you pass as a parameter only the id of the div which contains the behavior. This is the same thing as creating a Tabs instance with the options object and passing only the container parameter:

SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs({container: "tabSet"});
});

In which tabSet is the id of the tab system container.

Nested tabs

In this first mode, in order to use nested tabs you need the following markup and javascript code. This is only valid for this first mode. On the other modes, you need to create the nested tabs instances separately and add them to the markup.

<div id="tabSet">
    <ul class="sapo-tabs-nav">
        <li><a href="#firstTabName">first tab name</a></li>
        <li><a href="#secondTabName">second tab name</a></li>
    </ul>
    
    <div id="firstTabName" class="sapo-tabs-container">
        first tab content
    </div>

    <div id="secondTabName" class="sapo-tabs-container">
        second tab content

		<div id="tabSet2">
		    <ul class="sapo-tabs-nav">
		        <li><a href="#firstNestedTabName">first tab name</a></li>
		        <li><a href="#secondNestedTabName">second tab name</a></li>
		    </ul>

		    <div id="firstNestedTabName" class="sapo-tabs-container">
		        first nested tab content
		    </div>

		    <div id="secondNestedTabName" class="sapo-tabs-container">
		        second nested tab content
		    </div>
		</div>
    </div>
</div>

With the following JavaScript?:

SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs(
		container: "tabSet",
		nested: {
			"secondTabName": new SAPO.Component.Tabs("tabSet2")
		}
	);
});

All the nested tabs instances need to be created in the "nested" parameter, associated to the tab system on which they will exist. You can have several levels of nested tabs, always declared in the same way.

In this first mode you can create links for a given tab, so you can use them instead the tabs menu. To do that, this link only needs to reference the anchor link of the wanted tab, and have the class sapo-tabs-innerlink. Example:

<a href="#stuff" class="sapo-tabs-innerlink">internal link</a>



Second mode - Add behavior to an html menu without content present on the page

This mode expects the existence of an HTML menu present on the page, with all the tabs content generated through javascript code. The needed HTML is the following:

<div id="tabSet">
    <ul class="sapo-tabs-nav">
        <li><a href="#firstTabName">first tab name</a></li>
        <li><a href="#secondTabName">second tab name</a></li>
    </ul>
</div>

The classes specified here are mandatory for the behavior to work.

You need the following javascript code inside a DOM ready or DOM loaded event:

SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs({
        container: "tabSet",
        tabs: [
            { content: "this is the first tab" },
            { content: "this is the second tab" }
        ]
    });
});

The content parameter needs to be a string with HTML code or a function which returns HTML code (read more about this).

If you want to load HTML content through a GET XMLHttpRequest you specify the request URL on the href parameter of the link and set the remote parameter to true. For more specific needs you can use the callback on the content parameter Example no how to load AJAX content:

<div id="tabSet">
    <ul class="sapo-tabs-nav">
        <li><a href="#firstTabName">first tab name</a></li>
        <li><a href="request.html">second tab name</a></li>
    </ul>
</div>


SAPO.Dom.Event.observe(document, "dom:loaded", function(){
    new SAPO.Component.Tabs({
        container: "tabSet",
        tabs: [
            { content: "this is the first tab" },
            { remote: true }
        ]
    });
});



Third mode - create tabs programatically

This mode allows tabs to be created through JavaScript? and added to the DOM through JS. For this, you need the following code:

var tabs = new SAPO.Component.Tabs({
    tabs: [
        { title: "first tab title", content: "this is the first tab" },
        { title: "second tab title", content: "this is the second tab" }
    ]
});
s$("tabSet").appendChild(tabs.getTabs());

In this mode, you create a Tabs instance which has a getTabs method which will return the DOM objects generated according to the specified options. These objects can then be injected on the DOM. In this mode you need to specify a title parameter for each tab, which will be the name of the tab on the menu.

The content parameter should be a string with HTML code or a function which returns HTML code. If you want to load HTML content through a XMLHttpRequest you can use the remote parameter instead of the parameter content to specify an url which returns HTML through a GET request. For more specific needs you can use the callback on the content parameter. Example of how to load AJAX content:

var tabs = new SAPO.Component.Tabs({
    tabs: [
        { title: "first tab title", content: "this is the first tab" },
        { title: "second tab title", remote: "remote.html" }
    ]
});

After creating the instance, the getTabs method returns the objects created for the tab set defined on initialization, which should then be injected on the DOM:

var tabSet = document.createElement("DIV");

tabSet.appendChild(tabs.getTabs());

document.body.appendChild(tabSet);



Callback on the content parameter

The content parameter can accept a callback instead of a string. This callback needs to return HTML which will then be injected on the tab or, in case this isn't possible due to the use of asynchronous calls, the callback receives an object container as a parameter with a loadContent method through which you can load content into the tab. Example:

var tabs = new SAPO.Component.Tabs({
    tabs: [
        {
            title: "first tab title",
            content: function(container){
                container.loadContent("<p>some html</p>");
            }
        }
    ]
});



Other options

The object passed to the constructor SAPO.Component.Tabs can also use the following options:

  • cache: true|false - this option is only used on the second and third modes. By activating this option, the tabs are only created once and the AJAX requests will only happen once. If the content can change on each AJAX request, you shouldn't use this option.
  • tabNavClass - name of the class applied to the tabs menu
  • activeNavClass - name of the class applied to the currently active menu tabs item
  • tabContainerClass - name of the class applied to the container or containers of tabs
  • activeContainerClass - name of the class applied to the currently active container
  • nojsContainerClass - name of the class which will be removed from the top level container, for when JS is not available (first mode only)
  • innerLinkClass - name of the class for internal links
  • nested - object which contains the nested tabs on the first level below this tab system (first mode only)
  • loadCallback - callback executed after the loading of any tab. Gets as parameters the DOM object of the tab container and the object passed on the tabs array, for this tab.
  • Each object of the tabs array allows you to specify an option called events which is a callback applied to the specified tab. It's similar to loadCallback, but applied to one tab only. Gets as parameter the DOM object of the tab container.