CodeStereotabs: Tabs with Prototype and Scriptaculous


Features

Stereotabs is a small and lightweight script that allows you to easily add interactive tabs to your web pages. Very much inspired by Kevin Miller's Accordion script, this bit of code makes creating an smooth tabbed interface easy.

  • Unobtrusive » All behaviors are added after page load and don't muck up your html. Visitors without javascript will see all of your content.
  • Simple » You can add it to your existing pages quickly with just a few lines.
  • Small » Uncompressed the source is 82 lines long. 2k!
  • It Remembers » Your tabs are actually links to page anchors. Reload the page and the same tab will remain active.

Setup

Download the code.
Stereotabs requires prototype.js and effects.js (part of the scriptaculous library). If you don't want the fade-in / fade-out effect, you can do without effects.js

Include the source files.


<script type="text/javascript" src="js/prototype.js"></script>
<script type="text/javascript" src="js/effects.js"></script>
<script type="text/javascript" src="js/stereotabs.js"></script>
    

Initialize the tabs.


<script type="text/javascript">
//<![CDATA[
Event.observe(window, 'load', loadTabs, false);
function loadTabs() {
var tabs = new tabset('container'); // name of div to crawl for tabs and panels
tabs.autoActivate($('tab_first')); // name of tab to auto-select if none exists in the url
}
//]]>
</script>
    

Create your tabs.
Stereotabs will crawl the DOM element you specify for elements that contain the "tab" class and "panel" class (you can specify class names if you wish). It then uses these elements' ID tags to know which element to display when each tab is clicked. Here is a simple example. Notice each tab has the class "tab" and each tab content has the class name "panel". Also not that the IDs of the tabs match up with the IDs of the tab content.


<div id="container">
<ul id="tabnav">
  <li><a href="#first" id="tab_first" class="tab">Tab One</a></li>
  <li><a href="#second" id="tab_second" class="tab">Tab Two</a></li>
  <li><a href="#third" id="tab_third" class="tab">Tab Three</a></li>
</ul>
<div id="panel_first" class="panel">
  Here is the content for the first tab.
</div>
<div id="panel_second" class="panel">
  Here is the content for the second tab.
</div>
<div id="panel_third" class="panel">
  Here is the content for the third tab.
</div>     
</div>
        

Configuration

You can create a tab set and pass it a few options to customize it to your current page structure. By default, the code will search for tabs by using the class name "tab", and tab content using the class name "panel". It also will apply the class name "selected" to the currently selected tab.

You may also have noticed that the id attributes for the tags and tag content started with either "tab_" or "panel_". This is a way to link a tab with its specific content while still keeping the ids unique. You can change these in the configuration as well.

Finally, if you wanted, you can turn off the fade effect, and also change the event that triggers the tab activation.

Below is an example of how you can pass options to your tab set.


var tabs = new tabset('container', {
classNames: {
  tab:        'tab',      // class name used to identify the tabs
  panel:      'panel',    // class name used to identify the tab content
  tabActive:  'selected'  // class name added to the active tab
},                        
ids: {                    
  tab:        'tab_',     // what to strip off the tab id to get the tab name
  panel:      'panel_'    // what to strip off the tab content id to get the tab name
},                        
onEvent:      'click',    // perhaps you want to activate on mouseover? not recommended
effects:      true        // set this to false if you do not want to include effects.js
});
          

Download

New version works with FF3 and Prototype 1.6! Download the new version of stereotabs 1.6.

Download the old version for Prototype 1.5 (won't work with Firefox 3) here. Or, if you just want the source and not the whole archive, you can view stereotabs.js.

53 Responses to “Stereotabs: Tabs with Prototype and Scriptaculous”

  1. This is so cool. I’m wondering whether this stereotabs can be integrated with velocity menu

    By fadhlirahim on Jul 24, 2007

  2. I’m wondering if people think it would be better to eliminate the IDs and class names from the tabs themselves and just rely on the href tag?

    @fadhlirahim: I bet it would work with velocity menu… just include both javascript sources and initialize stereotabs second. it should be able to add the onclick event in conjunction with any existing tab events.

    By smeves on Jul 24, 2007

  3. Clicking on tabs too fast screws everything up…
    Maybe you should consider putting “limit: 1″ into Effect’s queue option?

    Best,
    kangax

    By kangax on Jul 26, 2007

  4. is there any way to load tab contents dynamically?

    By Yücel Dağlar on Jul 28, 2007

  5. @Yücel
    Sure, just use prototypejs’ Ajax.Updater
    http://prototypejs.org/api/ajax/updater

    By naholyr on Jul 31, 2007

  6. Very nice guys!

    By Ben Arwin on Aug 1, 2007

  7. Very nice!
    If you want to see it in real world:

    http://www.ihr-implantologe.eu

    Thank you very much!

    By Michael Konjevic on Sep 1, 2007

  8. Hello,

    Very usefull script. Only thing is when you refresh the page, you see all of the content flashin before the content fades. Is there a way to fix this? Hope to see a reply.

    Thx.
    len

    By Lenrick on Nov 4, 2007

  9. Len,

    If you add a “display:none” style to your panels they will not display when the page loads. However, this will make your page inaccessible to visitors with javascript turned off. It’s a trade-off.

    By Scott Meves on Nov 4, 2007

  10. Thank you for a great script! It works great although I encoutered a small problem when using it without effects. I think this is what you meant (from line no 55-67):

    
       if (this.showPanel) {
          if (this.options.effects) {
            new Effect.Fade(this.showPanel, {queue: 'front'});
          } else {
            $(this.showPanel).hide();//$(this.currentPanel).hide();
          }
        }
    
        if (this.options.effects) {
          new Effect.Appear(this.currentPanel, {queue: 'end'});
        } else {
          $(this.currentPanel).show(); //$(this.showPanel).show();
        }
    }}}
    
    

    By Joel on Nov 5, 2007

  11. Hi Scott,

    Thx for your fast reply. It worked.

    Len.

    By Lenrick on Nov 5, 2007

  12. doesn’t work with prototype 1.6
    Any fix?

    By Chris on Nov 22, 2007

  13. Hey, Love the script! I just have a quick question, though… I was wondering if there was any way to highlight the selected tab using CSS? cheers. D.

    By Dennis hurley on Nov 29, 2007

  14. hey awsome script

    one thing though:

    is there a way to make it not flicker when you first come upon the tabbed page? (it seems that the script first loads, and displays the tabs, and then hides it)

    By david on Dec 5, 2007

  15. @david, check out my comment to Len above.

    (If you add a “display:none” style to your panels they will not display when the page loads. However, this will make your page inaccessible to visitors with javascript turned off. It’s a trade-off.)

    By Scott Meves on Dec 5, 2007

  16. lol omg

    i totally missed that

    By david on Dec 5, 2007

  17. Hi,

    Clicking several tabs very fast will display several tabs contents together. Is there anyway that can ensure only one tab content is display at a time?

    By samantha on Dec 16, 2007

  18. Yes, I noticed that the contents wil be displayed together if you click the tabs fast. It’s easy to reproduce this.

    Is this perhaps related to the fading effect?

    By Eric on Dec 17, 2007

  19. Whenever the tab is clicked, the page will jump back to the top. Does anyone know how to fix it?

    By Henly on Dec 18, 2007

  20. Thanks for this script. Everything works fine, except: I cannot switch off the fading effect. I tried to set effects: false in line 34. But then it doesn’t work anymore. Any suggestions?

    By Kate on Dec 19, 2007

  21. nice script!

    By An Vũ on Jan 1, 2008

  22. Thnx;
    But I have the same problem as Kate. If I set the effect to false It does not work anymore…

    By Bart on Jan 2, 2008

  23. Hi,
    Same problem as Samantha, whent he tabs are clicked even remotely fast the content overlaps inside.. Try clicking the demo above, it will happen.

    I am using Safari 3.0, and am experiencing the issue in all browsers..

    Thanks for any help on this!

    By Ben on Jan 14, 2008

  24. Anyone want to post and update to this script that fixes the issue? I’m short on time but plan on doing so in the future. I think we’ll have to add the Effect.Fade into an Effects queue.

    By Scott Meves on Jan 14, 2008

  25. Nice script.

    However, would like to know if we want to print the page, how can all the content be displayed?

    By Conan on Feb 13, 2008

  26. Conan, you could accomplish this by creating a new stylesheet for print.

    In that stylesheet you can add print-specific styles, such as making sure your tabs are visible:

    
    .panel {
       display: block;
    }

    By Scott Meves on Feb 13, 2008

  27. I have add a specific style sheet for print with “.panel {display: block;}”, however only the current tag is displayed and other content still be hidden. Please help. Thanks.

    By Conan on Feb 13, 2008

  28. Conan, If it’s not working perhaps it’s because the prototype functions hide() and scriptaculous’ Effect.Fade() set a display:none style directly to the elements you want to print. You have two options, which I will leave up to you to implement. You could make a print button on the page that when pressed would first make all the elements visible in the page before it prints (or you could make a printer-friendly version of the page without the tabs script). You could also rewrite the code so that instead of calling hide() you instead apply a new class name with something like $(element).addClassName(’hiddenTab’). and then make sure the inline this class would be in your normal stylesheet as:

    .hiddenTab { visibility: none; display: none }

    Then, in your printer stylesheet, you would override these styles:

    .hiddenTab { visibility: visible; display: block }

    By Scott Meves on Feb 13, 2008

  29. Thanks for the suggestion.

    How can I apply the addClassName function together with fade-in/fade-out effect?

    By Conan on Feb 19, 2008

  30. Really great piece of code. Just one objection, though. I don’t really like that orphaned exception. I mean, if I have set options.effects = false, throwing an exception saying Effects is missing is out of order.

    My first solution is to check for Effects after confirming I want it in the first place:

    //extend options
    if (this.options.effects && typeof Effect == ‘undefined’)
    throw(”Stereotabs requires including script.aculo.us’ Effects library!”);

    BTW, I changed the message a bit, as you can see.

    Anyway, it may be even better to degrade to options.effects = false and show a warning instead of an exception.

    cheers

    By J. A. Rodriguez on Mar 2, 2008

  31. Nice code. I’ve used this a few times and it works great. Have a new problem, though. I need to have links within the individual panels that should open other panels but I can’t figure out how to make them work. I tried using the relative and absolute url with the hash for the panel name, but the page doesn’t refresh since the browser just views these as anchor links. How can I use a text link to open a different panel?

    By cg on Mar 5, 2008

  32. I love the script, but for the life of me cannot get the current tab in a selected state. How was that created in the demo above?

    I see the stylesheets are just a tad different than what is here in the page as opposed to the downloaded file, but the changes don’t reflect the functionality as well.

    Any ideas? The site I’ve implemented the code at is here: http://www.mooshoopork.net

    By Evan on Mar 17, 2008

  33. Nevermind, figured it out.

    the class “ul#tab li a.active” needs to change to “ul#tabnav li a.selected” and that did the trick.

    Tested in firefox and IE 6 for PC.

    By Evan on Mar 17, 2008

  34. @Evan,

    The javascript adds a classname to the currently selected tab called “selected”. So, you could add a style like:

    ul#tabnav li a:hover, ul#tabnav li a.selected {
    background-color: #fff
    

    It looks like the selected state is working fine on your site in FF but not when I checked it in safari. You may need to add “!important” to your a.selected style.Looks like you fixed it while I was checking! Great work.

    By Scott Meves on Mar 17, 2008

  35. how can you turn off the effect?

    By damien on Mar 21, 2008

  36. Hello Scott,

    First of all - thanks for sharing good code, I’ve searched for proper tabbing solution, and right now - yours looks like a good fit.

    I want to offer few improvements for you to review, and possibly apply.

    //line 33
    fixHeight: true, //this is to automatically resize panels to have same size as highest one

    //line 46
    if(this.options.fixHeight) {
    var maxPanelHeight = this.panels.max(function(panel) {
    var visible = Element.visible(panel), height;
    Element.setStyle(panel, {position: ‘relative’, width: ‘100%’, left: ‘0px’});
    if (!visible) Element.show(panel);
    height = Element.getHeight(panel);
    if (!visible) Element.hide(panel);
    return height;
    });

    this.panels.each(function(panel) {
    panel.style.height = maxPanelHeight.toString() + ‘px’;
    });

    }

    By Andriy Tyurnikov on Apr 3, 2008

  37. Hi! Great job! Thanks! Just what I was looking for!

    Im working on creating a site for gamers and right now I’m using your script so users can watch “hot”-things posted on the site trough a div at the main page by clicking the tabs. The thing is that this function would be enhanced so friggin much if it would cycle trough all tabs automatically with js, instead of the user always having to click on the tabs to see the next panel. Like the one on this site: http://www.gameplayer.se. It’s exactly what I’m looking for except it’s in flash, wich sucks.

    So question! Is there an easy way to create this? Can’t belive it’s too hard :P Tips are appreciated :D

    Cheers
    Patrik

    By Patrik Ilola on Apr 16, 2008

  38. @Patrik:

    This is a great idea. If you are familiar with prototype.js, you would want to make use of the periodicalExecuter (http://www.prototypejs.org/api/periodicalExecuter) function to automatically call the ‘activate()’ method on the next tab. This is a quick example I just came up with and it probably won’t work right out of the box, but it might get you going if you feel like diving into it on your own.

    function showNextTab() {
          useNextTab = false;
    
          myTabset.tabs.each(function(tab) {
            console.log('using next tab?', useNextTab);
            if (useNextTab == true) {
              myTabset.activate(tab);
              return;
            }
            var tabName = tab.id.replace(myTabset.options.ids.tab,'');
            console.log(myTabset.currentPanel, myTabset.options.ids.panel+tabName);
            if (myTabset.currentPanel == myTabset.options.ids.panel+tabName) {
              // this is the active tab, so we want to use the next one
              useNextTab = true;
            }
          });
          // we did not find a follow up tab to activate, so we start at the beginning
          myTabset.activate(myTabset.tabs[0]);
        }
    
        new PeriodicalExecuter(showNextTab, 10);

    By Scott Meves on Apr 16, 2008

  39. @Scott

    Hmm. Actually I’m not that familiar with prototype.

    Maybe it’s too much to ask for, but is there any chance that you could help me out? Would really like to get it to work. I’m kinda stuck there. I bet that others would be interested too :)

    By Patrik Ilola on May 20, 2008

  40. I have to be honest– this is not high on the list right now. But, I’ll keep it in mind for future a future update. Maybe someone out there reading this will want to pitch in.

    By Scott Meves on May 20, 2008

  41. Okey! I understand! Thanks anyway!

    By Patrik Ilola on May 20, 2008

  42. I recommend the duration of effects to be set to 0.5 instead of the default Fade effect.

    By Fadhli Rahim on Jun 5, 2008

  43. this code is broken for use in Firefox3 RC2 due to a native implementation of getElementsByClassName which returns a node collection.

    it can be fixed by changing ‘getElementsByClassName’ to ’select’ and adding a ‘.’ before the class name.

    e.g.
    before : getElementsByClassName(’tab’)
    after : select(’.tab’)

    By Nick Sellen on Jun 5, 2008

  44. Well, thanks Nick for that tip. i just installed FF3 and started to panic a bit when i check the site using this script.

    out of curiosity, does this mean that FF3 is going break many script or just the one using getElementsByClassName function?

    i’m not sure if it’s such a major thing (newbie to js) but kind of odd if it impacts so many script to make such change with any fall back from FF, no?

    thanks again.

    cheers

    By julien on Jun 7, 2008

  45. Great script. I had a similar problem as Nick mentioned above, though. However, not with Firefox but with Safari 3 and Prototype 1.6. It’s working fine with Prototype 1.5, but in order to work with 1.6 you have to change the getElementsByClassName to select as in Nick’s comment.

    By Adrian Schoenig on Jun 14, 2008

  46. Nick : where do you change all of this, please ?
    i’ve made the changes in the stereotabs.js but that does not do the trick.

    regards.

    By foxmask on Jun 17, 2008

  47. Hi… Looks like bahzillions of people have upgraded to Firefox 3, and it doesn’t work with Stereotabs…

    I’m going to need to switch to another tabs system until a fix is released… any word on a timeframe?

    Stereotabs FTW!!! (once it works with FF3!) :)

    By Mike on Jun 20, 2008

  48. Just uploaded a new version that works with Firefox 3 and prototype 1.6. Thanks to Nick’s comment the fix was super easy. Thanks Nick!!!

    By Scott Meves on Jun 20, 2008

  49. still can’t get to work in FF3 - does something other than the .js files need to be updated?

    By evan on Jun 20, 2008

  50. I get the error “this.tabs.each is not a function”
    line 42 in stereotabs.js

    By evan on Jun 20, 2008

  51. found the problem…
    http://stereointeractive.com/blog/wp-content/uploads/code/stereotabs.zip

    isn’t the current…

    By evan on Jun 20, 2008

  52. the change of getElementsByClassName to select method is quite annoying…..the problem is prototype 1.6 have a disadvantage that it breaks when you gzip it..problem with the internal hack in method parameter conditioning
    (http://ajax.sys-con.com/read/464826.htm)

    is there any way that we could use the old prototype and still support FF3?or any solution about gzip-ing the new prototype?

    thanks alot…

    By Dan on Jul 13, 2008

  53. For the people who want to get rid of the relatively slow changing of the tab content (like damien), change the following lines:

    line 57:
    new Effect.Fade(this.showPanel, {queue: ‘front’});

    change to:
    new Effect.Fade(this.showPanel, {duration: 0.1, queue: ‘front’});

    line 64: new Effect.Appear(this.currentPanel, {queue: ‘end’});

    change to: new Effect.Appear(this.currentPanel, {duration: 0.1, queue: ‘end’});

    By Phunkk on Jul 16, 2008

Post a Comment

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word