SUBSCRIBE VIA RSS


Subscribe to our feed

Symfony Experts

Symfony Experts
If you have an urgent question for a symfony-related issue, this is the place to ask.

Topics

Stack Overflow


The old fashioned way

RECENT TUNES

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.

107 Responses to Stereotabs: Tabs with Prototype and Scriptaculous

  1. Dan says:

    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…

  2. Phunkk says:

    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’});

  3. Kate says:

    … the download page is quite confusing. the zip package comes with an old stereotab-library…!?

  4. David Fauber says:

    I was having trouble with the effects setting. My fix for setting effects to false broke things when effects was set to ‘true’, so I ended up just changing a couple of lines to ignore the effects setting (suited my purposes). Here is the modified js if anyone is interested:

    [code]
    var tabName = tab.id.replace(this.options.ids.tab,”);

    this.currentPanel = this.options.ids.panel+tabName;
    if (this.showPanel == this.currentPanel) {
    return false;
    }

    $(this.currentPanel).show();

    if ($(this.showPanel) != null){
    $(this.showPanel).hide();
    }

    this.tabs.invoke(‘removeClassName’, this.options.classNames.tabActive);
    tab.addClassName(this.options.classNames.tabActive);
    this.showPanel = this.currentPanel;
    [/code]

  5. Federico Bo says:

    Ciao.
    Thanks for your very useful code.

    A question: is it possible have two different and indipendent tabs set in the same page? For example at right USA(Alabama, Texas, Florida etc) and at left Europe(Italy, France, UK etc)
    I’ve done some test but without good result.

    Thanks

    Federico

  6. Coen Coppens says:

    @Federico Bo:

    You can use it twice without a problem. Just make sure you use different id’s in the second set and that you dont change the effect settings (so dont disable them).

  7. Chris says:

    Default security settings in IE7 prevent this script from running unless you allow it. Any way around that?

  8. Scott Meves says:

    I have no idea why that would be the case, nor do I use IE7… but please do share with us if you figure out what is going on. Does IE7 prevent javascript by default? This script doesn’t do anything out of the ordinary…

  9. Walter Lockhart says:

    Excellent script. Thank you for sharing.

    Whenever I click on a tab the page reloads and jumps to the top of the browser window. Can anyone advise on how to prevent this?

    Thanks in advance.

  10. Pingback: Weekly Top Standards-Most Gallery #25 | Castup

  11. Pingback: 7 Wordpress Theme Trends & How To Implement Them Yourself - ForTheLose.org

  12. Pingback: Top 5 Wordpress Tab Systems | PaulSpoerry.com

  13. Pingback: 7 tendances de Blogdesign - Comment les mettre en place sur votre blog ? | Le Journal du Blog

  14. Pingback: Notes on a new design | Nometech.com

  15. Pingback: Notes on a new design | WPShout.com

  16. Bryan Davis says:

    I used the script and it was working quite nicely, then it just broke and started loading it all into a single div. I ran error checker and it found the following errors:

    Error: element.dispatchEvent is not a function
    Source File: http://www.mysite.com/wp-content/themes/mytheme/js/prototype.js
    Line: 3972

    Error: this.panels.invoke is not a function
    Source File: http://www.mysite.com/wp-content/themes/mytheme/js/stereotabs.js
    Line: 45

    Any idea what would have caused it to suddenly break?

  17. Scott Meves says:

    If I had to guess, I’d say an unrelated js file may have a stray comma somewhere that is interfering with your javascript being evaluated properly. Either that, or a quick search on google would imply that the “element.displatchEvent” error hints that you are including Jquery and Prototype on the same page.

  18. Pingback: DinPattern » “Simply Ornate” Wordpress Theme

  19. Don says:

    Is it possible to select the color of the opacity change? Right now, it changes opacity to zero from the base Panel Div background color.

    I have a white background on my page and would like to keep the white background and black text. So the Panel Div needs to be white too. When I make the Panel Div dark it looks very odd with my layout. I would like to use the fade effect but make the Panel Dive dim dark black briefly then fade back to the original white. This would be more dramatic and obvious than just simply fading the text.

    I looked around at the code, but didn’t immediately see a way to achieve this.

    Thanks for any input you can share.
    Don

  20. Don says:

    I did forget to compliment you on your fantastic script. It is simply very cool. I’ve looked around a lot for a tab menu script that would be subtle, but cool, but not too basic. Mootools, Jquery and Prototype. I’ve been through them all. This one is simply perfect for what I want to do. I just regret that I don’t have a dark layout to capture the full effect. Hope there is a way to do what I’ve asked about.

    Thanks again

  21. Bryan says:

    I noticed this comment above and I don’t see an answer to it.

    “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

    I am having this issue on a site currently in development. It only happens with smaller browser windows. Anyone have a clue on how to fix this?

  22. Scott Meves says:

    @bryan, try adding a “return false;” at the bottom of the activate function.

  23. Bryan Davis says:

    @scott – I’ve tried adding return false; into the end of the activate:function(tab) in the stereotab.js, but that doesn’t solve the problem.

    This is the code I have (before the add).

    activate: function(tab) {
        var tabName = tab.id.replace(this.options.ids.tab,'');
        this.currentPanel = this.options.ids.panel+tabName;
        if (this.showPanel == this.currentPanel) {
          return false;
        }
     
     
        if (this.showPanel) {
          if (this.options.effects) {
            new Effect.Fade(this.showPanel, {queue: 'front'});
          } else {
            $(this.currentPanel).hide();
          }
        }
     
        if (this.options.effects) {
          new Effect.Appear(this.currentPanel, {queue: 'end'});
        } else {
          $(this.showPanel).show();
        }
     
        this.tabs.invoke('removeClassName', this.options.classNames.tabActive);
        tab.addClassName(this.options.classNames.tabActive);
        this.showPanel = this.currentPanel;
      }

    Where do I add the return false; to make it work?

  24. Scott Meves says:

    Hi Bryan, sorry for the misleading comment. I looked into it and the solution is to stop the event bubble on the “click” event on the links. What’s likely happening is the browser window is trying to scroll to the position of your named anchors. Here is a fix. You have to add an additional parameter to the activate method to catch the event, and then call Event.stop() on it.

    activate: function(tab, event) {
        var tabName = tab.id.replace(this.options.ids.tab,'');
        this.currentPanel = this.options.ids.panel+tabName;
        if (this.showPanel == this.currentPanel) {
          return false;
        }
     
        if (this.showPanel) {
          if (this.options.effects) {
            new Effect.Fade(this.showPanel, {queue: 'front'});
          } else {
            $(this.currentPanel).hide();
          }
        }
     
        if (this.options.effects) {
          new Effect.Appear(this.currentPanel, {queue: 'end'});
        } else {
          $(this.showPanel).show();
        }
     
        this.tabs.invoke('removeClassName', this.options.classNames.tabActive);
        tab.addClassName(this.options.classNames.tabActive);
        this.showPanel = this.currentPanel;
        if (event) {
          Event.stop(event);
        }
      },
  25. Bryan says:

    Thank Scott…I’ll give this a try!

  26. Benjamin says:

    Hello,

    Amazing tutorial!! I have everything working almost perfectly now. My only issue is a screen jump.

    I have it setup to divide my post, comments, and trackbacks into different tabs. When I click on ‘post’ to go back to the actual article it jumps the page down. Is there a way to remedy this? I want the page to stay scrolled to the top no matter which tab is chosen.

    Thanks again!

  27. Scott Meves says:

    @Benjamin, check comment 68

  28. Benjamin says:

    Wow of course I missed the one right above me! Sorry Scott!

    Thanks it works great!!

  29. Don says:

    Great tab script! Very smooth. Can two instances of stereo tabs reside on the same web page, or would they conflict?

    Don

  30. Scott Meves says:

    @Don, I think you can create multiple instances on the same page, you just have to create new instances of the tabs class:

    // first tab set
    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
    // second tab set
    var otherTabs = new tabset('anothercontainer');
    otherTabs.autoActivate($('tab_first')); // name of tab to auto-select if none exists in the url
  31. Benjamin says:

    Hello Again Scott,

    Once again, great tutorial. However I am still having the jump issue. Maybe it’s a conflict on my end?

    I am using this bit of code just as was shown above:

    activate: function(tab, event) {
    var tabName = tab.id.replace(this.options.ids.tab,”);
    this.currentPanel = this.options.ids.panel+tabName;
    if (this.showPanel == this.currentPanel) {
    return false;
    }

    if (this.showPanel) {
    if (this.options.effects) {
    new Effect.Fade(this.showPanel, {queue: ‘front’});
    } else {
    $(this.currentPanel).hide();
    }
    }

    if (this.options.effects) {
    new Effect.Appear(this.currentPanel, {queue: ‘end’});
    } else {
    $(this.showPanel).show();
    }

    this.tabs.invoke(‘removeClassName’, this.options.classNames.tabActive);
    tab.addClassName(this.options.classNames.tabActive);
    this.showPanel = this.currentPanel;
    if (event) {
    Event.stop(event);
    }
    },

    I can click to a tab when the page initially loads, but it does nothing when I try to select a second tab.

    Thanks in advance for helping out a newbie trying to get his hands dirty!
    Benjamin

  32. Benjamin says:

    Ok I spoke to soon…

    I was missing the \’, event)\’ on the first line. I changed it but a cache issue was stopping me from seeing it.

    Sorry for the post (feel free to delete it).

    Thanks again for a great tutorial.

  33. Dong says:

    Hi Scott,

    About comment 68. I tried it but it only seems to fix IE browsers. It still scrolls down in FF 3.5. How can I fix this.

    More power!

  34. Dong says:

    Hi Scott,

    I’m sorry I got it right this time. My bad.

    However, a couple of things. I’d like to know how to pre-select the tabs. Also, would it be possible to have the ‘selected’ class appear in the li tag instead of the a tag?

    Thanks and more power.

  35. Pingback: Developer’s Snacks: Exploration on Web Tab Modules | Onextrapixel - Showcasing Web Treats Without Hitch

  36. Pritush says:

    i want to disable fade effect that appears when changing tabs, how to do this ?
    and also how to make tab text appear horizontal instead of vertical

  37. Pablo says:

    Dear Scott, I have a suggestion that would improve this (awesome) piec of code.

    Currently, if you click on multiple tabs very fast, all the according panels wil appear instead of just the last one.

    This can be fixed by queueing both the fade and the appear effect to the *end* of the effect queue. E.g. look for the line that says “new Effect.Fade(this.showPanel, […]);” and change ‘front’ to ‘end’.

    I think it is even more awesome this way.

  38. jbonez says:

    Any tips on how to set this up for wordpress? ive installed plugins and widgets but no idea how to impliment this into my site.

  39. Pingback: Tweets that mention Stereo Interactive & Design » Stereotabs: Tabs with Prototype and Scriptaculous -- Topsy.com

  40. Tommy says:

    Hello,

    Thanks for the script – so cool 🙂 Can anybody tell me how to dissable the fade effect between change of tabs or how to make fade effect go faster? Thanks.

  41. Pingback: evaneckard.com » “Simply Ornate” Free Wordpress Theme

  42. Francis says:

    Thanks for sharing the script! I suggest you put the scriptaculous effects in their own scoped queue ( queue: { position: ‘front’, scope: ‘tabs’ }} rather than the global queue so as not to interfere with other scripts on the same page which may also have scriptaculous effects.

  43. Meta4 says:

    I have the script working fine and everything looks great except for the fact that the tabs open in a new window rather than target=”_self” I have in the html code. WHen I got to the page and inspect code it’s still showing target”_blank”. Not sure what is overriding my html code. Any help would be greatly appreciated. Thank you for such a cool script.

  44. Tommy says:

    Is it possible to trigger a tab with a regular hyperlink? I have tried to trigger eg. Tab3 by adding #tab3 in the link, but nothing happens. Any help much appreciated.

  45. webmagic says:

    here is very quick fix for autoscroll on three tabs

    //

  46. Andrew says:

    Hi Scott,

    Thanks for the great script! Really cool.

    I was still having problems with the jumping of the screen, but I figured out it was that in the moment between panels appearing, when the height of the panels jumps to zero, it was actually my screen window moving up to compensate that the page was now shorter. This stackoverflow article tipped me off: http://stackoverflow.com/questions/243794/jquery-ui-tabs-causing-screen-to-jump/1635723#1635723

    Anyway, I fixed it by just assigning a height to the containing the tabs and panels that makes it taller than the tallest panel.

    Hope that helps some folks.

  47. Van says:

    How did you get Scriptaculous not to play havoc with my Google Maps served in iFrames? With me, the Appear effect moves the map display out of the frame. With Stereotabs, the map displays right where it’s supposed to. I don’t get it.

    See here on stackoverflow:
    <a href="http://stackoverflow.com/questions/5095090/scriptaculous-appear-effect-shifts-google-map-outside-visible-iframe-area&quot;

    Any ideas?

    Thank, great tabs!

    Van

  48. William says:

    In regards to comment 74, where do you put this? I know nothing about JS, so I’m not even sure where to begin on this. Thanks!

  49. Mikel Arzak says:

    Hello,

    Nice script. I have a problem. I use this script with forms and I would like to know if it’s possible to activate after ‘submit’ button is pressed, the tab that it was active before this button is pressed.

    Thanks for your help.