The Ditchnet JSP Tabs Taglib provides an incredibly simple toolkit for adding rich, sophisticated tabbed-pane GUI components to web-based user interfaces. The Tabs Taglib combines the powerful features of DHTML, Java, and JSP to allow you to create web-based tabbed interfaces that behave in a manner remarkably similar to what you would expect from a rich client toolkit like Java Swing.
The Tabs Taglib utilizes JavaScript and DHTML to respond to client-side, user-initiated events, while leveraging JSP and the Servlet API for rendering the tabbed components and persisting the state of individual selected tabs.
This means that the Tab components respond to user events without annoying round-trips to the server, but still manage to persist their state in the user's session -- accessed through the Servlet API's HttpSession. So the Tabs respond and repaint immediately but effortlessly persist their state!
Page authoring with the Tabs Taglib is extremely simple, and installing the toolkit is even easier. The Tabs Taglib comes with pre-built skins, and allows the use of custom CSS for entirely customized styles.
Tabs can be nested and combined with other JSP and JSTL custom tags -- there is even a mechanism included for simply targeting a specific selected tab (on the current page or another page) via a hyperlink.
What about accessibility? Doesn't excessive use of JavaScript limit the types of clients that can interact with your web site? Normally, yes... but we've taken great care to make sure that the Tabs Taglib exhibits Graceful Degredation. In other words, if the user has JavaScript turned off, the tabs still work.
All of the JavaScript-powered tab switching is automatically replaced with traditional (slower) hyperlinks and HTTP request/response cycles if the user has scripting disabled in his browser! Thus the Tabs Taglib is compatable with non-JavaScript enabled browsers, and text-based browsers such as Lynx. Try disabling JavaScript in your browser and click around the tabs on this page to see what we mean... All of the DHTML, none of the guilt.
The Tabs taglib is released under the very liberal BSD License. Go crazy and do whatever you like with it. The Tabs taglib is currently beta software, and not meant for production systems. The 1.0 version will include documentation beyond what is found on this website.
Thanks to the JSP and Servlet APIs, Installation of the Tabs Taglib is simple:
The Tabs Taglib is now installed. Yup, that's it.
You can now begin authoring web pages with Tabs as described next...
You may be wondering why the root directory of your web app must be writable... The Tabs Taglib includes a ServletContextListener that will automatically be registered for your web app -- you don't need to add anything to your web.xml deployment descriptor to register this listener -- the configuration for this listener is included in the taglib tld file in the JAR, and will be registered without additional effort.
This ServletContextListener's first job is to create a directory in the root of your web app named org.ditchnet.taglib. Next, the listener will copy the necessary CSS, JavaScript, and image resources from the JAR to this new directory. After dropping the JAR into your WEB-INF/lib directory, and reloading your web app, you will see these directories and files appear.
If you do not see these directories and files appear upon web app reload, there may be a permission issue in writing to your web app's root directory. Try to change this, and re-reload the web app.
Authoring JSPs using the Tabs Taglib is a breeze, and will be easy for anyone familiar with JSP (or even HTML) to pick up quickly.
Add the Tabs Taglib directive to your JSP, as well as an XHTML Transitional Doctype (recommended for CSS correctness and consistency across browsers -- see related article on Doctype Switching).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ page contentType="text/html" %>
<%@ taglib prefix="tab" uri="http://ditchnet.org/jsp-tabs-taglib" %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
Add the <tab:tabConfig /> tag to the page's HTML <head> element.
<head>
<tab:tabConfig />
</head>
This tag will effortlessly take care of creating the HTML <script> and <link> tags that link the necessary CSS and JavaScript libraries to the page. Of course, you may add additional scripts or styles to override the defaults.
Add a <tab:tabContainer> tag for every tabbed pane grouping you wish to create.
<tab:tabContainer>
</tab:tabContainer>
Give the <tab:tabContainer> tag an HTML id attribute that is unique across your application (servlet context).
<tab:tabContainer id="foo-bar-container">
</tab:tabContainer>
This id must be unique in your application, as it is used to persist this container's selected tab index in the user's session.
Add a nested <tab:tabPane> tag for every tab you wish to add to the tab container.
<tab:tabContainer id="foo-bar-container">
<tab:tabPane></tab:tabPane>
<tab:tabPane></tab:tabPane>
</tab:tabContainer>
Give each <tab:tabPane> tag a required id and tabTitle attribute. The id will be passed through to the HTML without change, and the tabTitle will be used to render the title in this tab pane's clickable tab at the top of the tab container. Just like in HTML, the id must be unique for this page.
<tab:tabContainer id="foo-bar-container">
<tab:tabPane id="foo" tabTitle="Foo!"></tab:tabPane>
<tab:tabPane id="bar" tabTitle="Bar!"></tab:tabPane>
</tab:tabContainer>
Add HTML or JSP content where desired.
<tab:tabContainer id="foo-bar-container">
<tab:tabPane id="foo" tabTitle="Foo!">
Foo is cool!
</tab:tabPane>
<tab:tabPane id="bar" tabTitle="Bar!">
<c:out value="Bar is cooler!" />
</tab:tabPane>
</tab:tabContainer>
Voila!
The Tabs Taglib uses pure CSS for layout, comes with two pre-defined CSS skins, and allows for the creation of custom CSS skins as well.
The skin used on the main tabs on this page is called "Default", and is meant to appear very neutral. Another pre-defined skin is also provided: "Invisible". The Invisible skin causes the tabs containing the tab titles to not be rendered, thus making possible a wizard effect... see the Navigate tab for more details.
So how do you specify the skin for a specific tab container? Easy! Just add the skin attribute to any <tab:tabContainer> tag as below:
<tab:tabContainer id="foo-bar-container" skin="Invisible">
<tab:tabPane id="foo" tabTitle="Foo!">
Foo is cool!
</tab:tabPane>
<tab:tabPane id="bar" tabTitle="Bar!">
<c:out value="Bar is cooler!" />
</tab:tabPane>
</tab:tabContainer>
The skin attribute is optional, and providing no value will give the same results as providing skin="Default". The skin attribute value is case-insensitive, so "Default" is the same as "default" or "DEFAULT".
WARNING: Due to CSS limitations, it is not currently possible to nest a tab container within another container with a different skin. So, it is recommended that nested tab containers have the same skin specified (implicitly or explicitly) as their enclosing tab container.
If you're an experienced DHTML web developer, and you're reading about the Tabs Taglib, you're probably getting a little nervous... If you begin using the Tabs Taglib, it's only a matter of time before your clients begin asking for remote hyperlinks to target specific tabs on a tabbed page. That sounds difficult, doesn't it? How do you make sure that a specific tab is selected on a page when you link to it?
Rest easy, the problem has already been solved. The Tabs Taglib contains a tag that will target non-nested tabs (support for targeting nested tabs is slated for 1.0). This tag is called <tag:tabLink> and is authored like so:
<tab:tabLink href="/mycontext/mypage.html" selectedTabPaneId="my-targeted-tab-pane">
This link targets a specific tab on another page.
</tab:tabLink>
As you can see, you treat the <tab:tabLink> tag much like a normal HTML <a> tag. Provide the tag with an href attribute with a context-relative url (relative your application, or servlet context).
Add one required attribute:
You may also provide the <tabLink> tag with an id attribute that will be passed through to the resulting HTML (known as a pass-through attribute in JSF). Use this for CSS or JavaScript references.
<tab:tabLink id="my-link" href="/mycontext/mypage.html" selectedTabPaneId="my-targeted-tab-pane">
This link targets a specific tab on another page.
</tab:tabLink>
A hyperlink will be rendered on the page that will link the referenced page with the indicated tab selected.
Here's the best part... if you remove the href attribute you indicate that the targeted tab is located on the current page, and the indicated tab will instead be activated via lightning-fast DHTML with no new HTTP request! This requires no extra effort on the part of the page author... the <tab:tabLink> handles the JavaScript on it's own!
Here's an example:
Two other tags included in the Tabs Taglib are the <tab:nextTabButton> <tab:prevTabButton> tags. These tags can be associated with a specific tab container via their tabContainerId attribute, and allow the user to click through the tabs quickly by pressing one button repeatedly.
By setting a tab container's skin attribute to invisible, and linking a <tab:nextTabButton> tag and a <tab:prevTabButton> tag to that tab container, a Wizard effect can be acheived!!!
When authoring, add an optional id attribute, and the tabContainerId attribute to associate the buttons with a specific tab container.
<tab:prevTabButton id="prev-button" tabContainerId="my-targeted-tab-container">PREV</tab:prevTabButton>
<tab:nextTabButton id="next-button" tabContainerId="my-targeted-tab-container">NEXT</tab:nextTabButton>
Here is an example of a tab container with associated next and prev tab buttons:
And here is an example of a tab container with a skin attribute of invisible with associated next and prev tab buttons:
Here's the source:
<tab:tabContainer id="next-prev-container2" skin="invisible">
<tab:tabPane id="pane2-1" tabTitle="One">1. Here is tab One.</tab:tabPane>
<tab:tabPane id="pane2-2" tabTitle="Two">2. This is tab Two.</tab:tabPane>
<tab:tabPane id="pane2-3" tabTitle="Three">3. Finally, tab Three.</tab:tabPane>
</tab:tabContainer>
<div>
<tab:prevTabButton tabContainerId="next-prev-container2">PREV</tab:prevTabButton>
<tab:nextTabButton tabContainerId="next-prev-container2">NEXT</tab:nextTabButton>
</div>
What if you want to write custom JavaScript event handler functions that are called whenever a tab is switched? The Tabs Taglib includes a mechanism for specifying your own custom JavaScript tab listener functions.
First, write a JavaScript function that is in the global scope that accepts a single parameter, very similar to normal JavaScript event handlers:
function myListener(evt) {
// a tab was clicked, and made visible. take action here
var selectedTabPane = evt.getTabPane(); // HTMLDivElement reference to
// the div containing the tab pane.
var selectedTab = evt.getTab(); // HTMLDivElement reference to
// the div that is the actual tab
// at the top of the container with
// the tab title.
var tabContainer = evt.getTabContainer(); // HTMLDivElement reference to
// the div wrapping the entire
// tab container.
doSomethingInteresting(selectedTabPane,selectedTab,tabContainer);
}
Say, what's that function argument named evt, exactly? It's an instance of the JavaScript class org.ditchnet.jsp.TabEvent.
This is a JavaScript class that provides information about the tab event that has just occurred, such as the event source (the selected tab), the selected index, the selected tab's tab container, and more. See the JSDoc API documentation for full details.
So how do you register this event listener with the appropriate tab? Use the jsTabListener attribue of the <tab:tabContainer> tag:
<tab:tabContainer id="my-container" jsTabListener="myListener">
<!-- tabs here...-->
</tab:tabContainer>
That's all it takes to register a JavaScript tab event listener... now your custom function will be called with the TabEvent instance every time a tab in the given tab container is switched.
There is no way to register a tab listener on just one tab, it must be done per tab container as shown above. That's fine though, because you can always inspect the TabEvent parameter sent to your function to determine which tab was selected.
The Tabs Taglib is no more or less compatable with JSF than any other JSP taglibs (including the JSTL). There are many well-documented issues with using JSF and JSP together at this time... the JSF 1.2 spec and JSP 2.1 spec aim to fix these problems, and should be released shortly.
I have personally experimented with placing several different JSF components and layouts within the Tabs Taglib components with much success, and am generally very pleased with the outcome.
We've taken great care to make sure that the Tabs Taglib embraces the concept of Graceful Degredation. In other words, if the user has JavaScript turned off, a page that uses the tabs still "work".
All of the JavaScript-powered tab switching in the Tabs Taglib is automatically replaced with traditional (slower) hyperlinks and HTTP request/response cycles if the user has scripting disabled in his browser! Thus the Tabs Taglib is compatable with non-JavaScript enabled browsers, text-based browsers such as Lynx, and other devices that assist in making the web accessible to people with different capabilities. Try disabling JavaScript in your browser and click around the tabs on this page to see what we mean... All of the DHTML, none of the guilt.
The Tabs Taglib is Free Software released under the BSD License and is currently available as a pre-release beta package. The Tabs Taglib is not considered ready for production systems just yet. Please try out the taglib and send feedback , so we can reach the 1.0 milestone! Certain aspects of the API documented on this webpage may change before the 1.0 release.
If you would like to make a donation to fund the future development of the Tabs Taglib, you may do so by clicking the button below...
Documentation generated using the following excellent tools:
The JSP Tabs Taglib is developed by Todd Ditchendorf.
Please contact Todd with all suggestions, criticisms and praise.
If you would like to make a donation to fund the future development of the Tabs Taglib, you may do so by clicking the button below...