Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web

A Simple JavaScript Tabbed Interface

5.00/5 (1 vote)
12 Apr 2016CPOL5 min read 12.4K   140  
Provides a skeleton tabbed browser interface implemented with JavaScript and CSS that supports tab content resizing and print formatting

Introduction

I recently decided to convert a couple of Java based applications into ASP.NET web apps, and the nature of these apps' output suggested that a tabbed interface would be effective. A web search for examples of tabbed browser interfaces provided a number of HTML/CSS/JavaScript based solutions: some very clever and a few demonstrating elegant use of CSS. Because my conversions require the integration of C# aspx code with the HTML, I was looking for as simple and transparent a solution as possible, supporting just the features my applications require. In the end, I decided it would be worth the effort to roll my own approach to obtain code that would be easy to integrate with the required server-side C# code, and this article presents the framework of my solution. It provides a tabbed interface using about 75 lines of HTML, JavaScript and CSS that supports resizeable bordered output in each tab and provides for printing each tab's content even when the output spans multiple pages. JavaScript is required for this tabbed interface, and it is not designed to degrade gracefully with browsers that do not support JavaScript.

Here's what the demo output looks like:

Image 1

Background

Typical tabbed interfaces implement an HTML defined selector such as an unordered list of links or group of radio buttons, then style these choices with CSS to look like tabs. The content associated with each tab is enclosed in a div that is styled as displayed or hidden as each tab is selected or deselected. The implementing JavaScript code reacts to clicking a tab by changing the style of each tab and div.

Using the Code

We'll look at the HTML body first, then the JavaScript and CSS components.

Each tab is defined by a link in a list item in the "tabSelect" unordered list and a div that must have a "class" value of "tabs" and a unique id. The actual tab content replaces the "Tab n content goes here" text. To add a tab, a li is added to the unordered list incorporating the appropriate showTab(n) function call and tab label, and a div is added in the corresponding (nth) position in the collection of divs with the "tabs" class value.

An optional statement defining a button following the "Tab x content goes here" div in each "tabs" class supports reformatting of each tab's content for printing by the browser when the "Printer Friendly Format" button is clicked. The content of all of the tabs is in a single HTML file, so printing a single tab's content without reformatting is not intrinsically possible using the browser's print capability. Clicking the back button after viewing the Printer Friendly Format restores the tabbed interface. The nested divs allow for extraction of the tab's content without the HTML defining the "Printer Friendly Format" button.

HTML
<ul id="tabSelect">
    <li><a href="#" onclick="showTab(0);" 
    class="tablinks">This is tab0 label</a></li>
    <li><a href="#" onclick="showTab(1);" 
    class="tablinks">This is tab1 label</a></li>
</ul>

<div class="tabs" id="tab0Content">
    <div id="tab0HTML">
        Tab 0 content goes here
    </div>
    <p><input type="button" 
    value="Printer Friendly Format" 
    onclick="printFormat(tab0HTML);"></p>
</div>

<div class="tabs" id="tab1Content">
    <div id="tab1HTML">
        Tab 1 content goes here
    </div>
    <p><input type="button" 
    value="Printer Friendly Format" 
    onclick="printFormat(tab1HTML);"></p>
 </div>

The body tag defines the actions to take when the page is loaded (select leftmost tab) and when it is resized (redefine borders and reselect the tab that was active when the resize action was taken):

HTML
<body onload="showTab(0);" onresize="resizeFlag=true;showTab(lastTabSelected);">

The JavaScript showTab(n) function has a single parameter (the tab to activate) and is used to invoke the style changes that control the appearance of the tabbed output. When first called, the function sets up arrays identifying the links and divs and determines the number of tabs that have been defined.

Next, the function iterates through the links and divs, styling each using the setAttribute function and style property as active or inactive. The background-color in the selected tab's link style should match the background-color specified in the style section for the div.tabs selector. Note that the bottom padding for the selected tab is slightly larger than for the unselected tabs (.41em vs. .3em). This causes the tab color for the selected tab to overwrite the tab's border, connecting the tab to the tab content. The minimum value that works is browser dependent, but .41 seems to be a good compromise.

Finally, if the resizeFlag is true, the dimensions of the divs are adjusted to account for the changed dimensions of the browser window. This allows the border to be resized.

The printFormat(id) function uses the innerHTML property to extract the HTML code associated with a single tab identified by its id, then displays it in a new window that can be printed using the browser's print capability. This web output excludes the tabs, border and "Printer Friendly Format" button. The browser's back button can be used to return to the tabbed output.

JavaScript
var links = new Array();
var divs = new Array();
var tabCount;
var lastTabSelected = -1;
var resizeFlag = true; //resize divs when true
function showTab(selectedTab) {
    if (lastTabSelected == -1) { //use -1 as init flag
        links = document.getElementsByClassName
        ("tablinks"); //links must have class name "tablinks"
        divs = document.getElementsByClassName("tabs"); //divs must have class name "tabs"
        tabCount = Math.min(links.length, divs.length); //should be equal counts
    }
    for (var i = 0; i < tabCount; i++) {
        if (i == selectedTab) {
            //Select this tab by changing the style
            links[i].setAttribute("style",
                "background-color: yellow; 
                font-weight: bold; padding: 0.3em 0.3em 0.41em 0.3em;");
            divs[i].style.display = "";
        } else {
            //Deselect the inactive tabs by changing the style
            links[i].setAttribute("style",
                "background-color: lightgray; 
                font-weight: normal; padding: 0.3em 0.3em 0.3em 0.3em;");
            divs[i].style.display = "none";
        }
        if (resizeFlag) {
            divs[i].style.height = (window.innerHeight - 60) + "px";
            divs[i].style.width = (window.innerWidth - 30) + "px";
        }
    }
    lastTabSelected = selectedTab; //to redisplay active tab after resize event
    resizeFlag = false;
} //showTab()
    
function printFormat(tabId) {
    var htmlStr = "<!DOCTYPE html><html><body>" + 
    tabId.innerHTML + "</body></html>";
    document.open(); document.write(htmlStr); document.close();
} //printFormat()

The style section defines static aspects of the appearance of the tabs and content areas. Note that the hover pseudo-class employs the !important option to raise the priority of the tab color when it is under the cursor. If not so flagged, the color assigned in the showTab(n) function will prevail.

The background color specified in the div.tabs style should match the color specified in the showTab(n) function for the active tab.

Setting overflow: auto in the div.tabs style definition automatically provides scroll bars if the tab's content overflows the bordered display area.

CSS
ul#tabSelect li { display: inline; }
ul#tabSelect { list-style-type: none; margin: 15px 0 0 0; padding: 0 0 0.3em 0; }
ul#tabSelect li a { color: black; border: 1px solid black; border-bottom: none; 
text-decoration: none; border-top-left-radius: .5em; border-top-right-radius: .5em;  }
ul#tabSelect li a:hover { background-color: lightblue!important; }
div.tabs { border: 1px solid black; padding: 5px; overflow: auto; background-color: yellow; }

Credit Where Credit is Due

While there are quite a few approaches to building a tabbed web page interface accessible through web searches, and there is a lot to be learned by examining the examples found by searching for a subject like "how to create tabs in html page", I'll end by mentioning (and providing links to) just a couple that I found especially interesting and/or useful.

The approach represented by my example was most influenced by this article on elated.com that is somewhat more complicated than my code, but does claim to degrade gracefully when JavaScript is not available.

Another approach that I that I'd count as one of the clever/elegant class of solutions is provided here on css-tricks.com. It makes use of radio buttons as the tab selectors and is implemented purely with CSS: no JavaScript. This article also provides links to several other approaches to providing tabbed content.

Points of Interest

Here is an example of the tab code integrated with an ASP.NET ID3 rule induction application. An interim version of the app may be accessed here: Run e2gRuleInduction id3 Application. In this application, the output displayed in each tab is generated at run time by invoking a method in a server side C# component.

Image 2

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)