Wednesday, July 2, 2008

How to Create Spry Tabbed panels with the tabs at the bottom

Spry Tabbed panels in 1.6.1 allow you to have your tabs at the top or on the left. Dreamweaver CS3 & CS4 (try the CS4 beta) will allow you to insert the tabs on the top, but it's pretty easy to change to vertical tab on the left by swapping out the class for the widget wrapper from TabbedPanels to VTabbedPanels. See the Spry Tabbed Panels documentation for more info on how the default tabbed panels work.

However, if you want you tabs to appear on the bottom of the panels, then you're outta luck, by default that is. Fortunately the Tabbed Panels are pretty easy to tweak to allow you to have your tabs on the bottom, by making three small changes. The first is to reorder the code that comprises the widget such that the container for the tabs is after the container for the panel content. So you move from:
<div id="TabbedPanels1" class="TabbedPanels">
<ul class="TabbedPanelsTabGroup">
<li class="TabbedPanelsTab" tabindex="0">Tab 1</li>
<li class="TabbedPanelsTab" tabindex="0">Tab 2</li>
<li class="TabbedPanelsTab" tabindex="0">Tab 3</li>
<li class="TabbedPanelsTab" tabindex="0">Tab 4</li>
</ul>
<div class="TabbedPanelsContentGroup">
<div class="TabbedPanelsContent">Content 1</div>
<div class="TabbedPanelsContent">Content 2</div>
<div class="TabbedPanelsContent">Content 3</div>
<div class="TabbedPanelsContent">Content 4</div>
</div>
</div>

To:
<div id="TabbedPanels1" class="TabbedPanels">
<div class="TabbedPanelsContentGroup">
<div class="TabbedPanelsContent">Content 1</div>
<div class="TabbedPanelsContent">Content 2</div>
<div class="TabbedPanelsContent">Content 3</div>
<div class="TabbedPanelsContent">Content 4</div>
</div>
<ul class="TabbedPanelsTabGroup">
<li class="TabbedPanelsTab" tabindex="0">Tab 1</li>
<li class="TabbedPanelsTab" tabindex="0">Tab 2</li>
<li class="TabbedPanelsTab" tabindex="0">Tab 3</li>
<li class="TabbedPanelsTab" tabindex="0">Tab 4</li>
</ul>
</div>

This change allows for easy display of the tabs at the bottom, because the tabs are now below the content panels.


Then you need to tweak the CSS a bit. You can change the code in the SpryTabbedPanels.css, but you may need the default for some other tabbed panel instance. So if you add the following style block to your page (or add it to a separate CSS file):
<style type="text/css">
<!--
.TabbedPanelsTab {
position: relative;
top: -1px;
float: left;
padding: 4px 10px;
margin: 0px 1px 0px 0px;
font: bold 0.7em sans-serif;
background-color: #DDD;
list-style: none;
border-left: solid 1px #CCC;
border-bottom: solid 1px #999;
border-top: solid 1px #999;
border-right: solid 1px #999;
-moz-user-select: none;
-khtml-user-select: none;
cursor: pointer;
}
.TabbedPanelsTabSelected {
background-color: #EEE;
border-top: 1px solid #EEE;
}
-->
</style>

If you compare the selectors to the matching styles in SpryTabbedPanels.css (.TabbedPanelsTab selector lines 67-83, and .TabbedPanelsTabSelected selector lines 105-108), you'll note that there are only two changes, moving from "top:1px;" to "top:-1px" for .TabbedPanelsTab and moving from "border-bottom: 1px solid #EEE;" to "border-top: 1px solid #EEE;". These changes will allow the bottom tab to overlap the bottom of the content making it look seamless for the "selected" tab.

So two down, one to go. The next change is in the JavaScript to allow the Spry Tabbed Panales widget to recognize the reordered tabs and content panels. As with the CSS, I'm putting this code into the page itself rather than modify the Spry files. Add the following to your page (pulled from SpryTabbedPanels.js lines 124-133 and lines 144-153):
<script type="text/javascript">
<!--
Spry.Widget.TabbedPanels.prototype.getTabGroup = function()
{
if (this.element)
{
var children = this.getElementChildren(this.element);
if (children.length)
return children[1];
}
return null;
};

Spry.Widget.TabbedPanels.prototype.getContentPanelGroup = function()
{
if (this.element)
{
var children = this.getElementChildren(this.element);
if (children.length > 1)
return children[0];
}
return null;
};
-->
</script>

The only changes here are moving from "return children[0];" to "return children[1];" in Spry.Widget.TabbedPanels.prototype.getTabGroup.

Both changes reflect the change in order of the tabs and the content panels within the Tabbed panel wrapper div (<div id="TabbedPanels1" class="TabbedPanels"></div>).

Save and preview your page and viola, bottom tabs on your Spry Tabbed Panels.

A couple of things to keep in mind. Dreamweaver won't properly display your tabs and content panels in design view, so you'll lose a bit there, and if your content panels are of differing heights, sat tab 1 content is 200 pixels high and tab 2 is 50 pixels high, then switching tabs will cause the bottom of the tabbed panels to move up and down (taking with them the tabs too).

The former issue can't be worked around without mucking about a good int in Dreamweaver's internals, the second probably can be worked around by setting specific heights for the content areas and then maybe setting an overflow:scroll to allow for content that is too tall to the height you set. I haven't tested that type of change, but should be something like that.

Labels:

31 Comments:

At July 23, 2008 12:33 AM , Blogger Julian Schoffel said...

Nice article mate. You mentioned the display issues with Dreamweaver in design view - I often find that happens for no apparent reason. I get divs pushed down in design view, often when there is a Spry menu. However it all works perfectly in browser.

Do you know by any chance what Adobe intend to do with Fireworks? I love that program and I hope they aren't going to neuter it in favour of Photoshop.

 
At July 23, 2008 12:14 PM , Blogger Danilo Celic said...

As there is a Fireworks CS4 beta on their Labs site, I'd say that Adobe is investing in Fireworks. You'll need a CS3 serial number to be able to use it for more than a couple of days. I've not investigated the CS4 beta much, so can't really tell you what all has been added that may be worth it to you, but I'd suggest taking a look at the release notes page for the Fireworks CS4 beta to see what has been added or improved and grab the beta to play around with it.

 
At August 11, 2008 4:15 PM , Blogger MyDayRegistry.com said...

Great post! I'm extremely new to the development world and your post gave me the guidance to push through a trouble spot.

I ran into another problem and know one seems to have an answer for it. When i'm editing the external css style sheet for this spry, I keep recieving a sharing violation. It stops me from saving the style sheet? Any ideas?

 
At September 8, 2008 12:06 PM , Blogger Kyle said...

Hi,

I've been searching high and low for advice on adding certain Spry effects to the Spry tabbed panels widget, and have found very little. basically, i want to add one of the default spry effects as a transition between the tabbed panels (a fade effect). i know the collapsible panels widget has animation built in, but is it possible to add transition effects to the tabbed panels widget? or is that simply not supported unless you can write code from scratch? (!)

any help would be much appreciated!

Kyle

 
At September 10, 2008 11:32 AM , Blogger Danilo Celic said...

@Kyle,

The showing and hiding of tabbed panels is in deed baked in, and so you'd need to re-write the Spry.Widget.TabbedPanels.prototype.showPanel method to be able to add in any animation effects you'd like to have.

This could be a good topic to look into for my presentation at MAX in November.

@mydayregistry,

Sorry, I've never seen that sharing violation error. I'd check for file permissions in the Spry folder contents, and then do some Google searches for "Dreamweaver sharing violation".

 
At September 11, 2008 6:11 AM , Blogger Kyle said...

This post has been removed by the author.

 
At September 11, 2008 6:12 AM , Blogger Kyle said...

Hi Danilo, thanks for your help, I'll definitely leave it well alone for now!

One other question though: is it possible to set spry tabbed panels to all be closed by default? i don't really want the content showing until one of the three tab buttons is clicked (you can see the page if that helps at: http://thing.websitewelcome.com/~createde/showcase.html

i realise that collapsible panels can be closed by default, but i want the layout functionality of tabbed panels... is there a fix you know of?

thanks again,

Kyle

 
At September 11, 2008 10:22 AM , Blogger Danilo Celic said...

@Kyle,

Just checked your page and it seems that you've found a way to do this by adding a "hidden" tab, one that has no content for the tab itself, and nothing in the content area.

I did a little looking and there is a option for the constructor that allows you to set the default tab, and that assumes that you're using an integer to identify the tab. So if you pass in 0.5 or even an empty string as the defaultTab option, then no tab content areas will show:

var TabbedPanels1 = new Spry.Widget.TabbedPanels("TabbedPanels1", {defaultTab:0.5});

or

var TabbedPanels1 = new Spry.Widget.TabbedPanels("TabbedPanels1", {defaultTab:''});

But I do like the hidden tab that you've come up with, as it doesn't require "breaking" the options parameter of the Tabbed panel, because you never know when they might "fix" defaultTab option so that it will only work with integers, and will ignore non-integers or strings.

 
At September 19, 2008 5:57 AM , Blogger Fredrik said...

Hi Danilo!

I would be so grateful if you could tell me if and in how I could manipulate the Spry Widget to make it select a specific tab (and its subcontent) on a specific page load.

See my page here using the standard Spry meny widget in Dreamweaver: http://www.narrativemedia.eu/ny/index.shtml

The default selection is always the tab on the very left no matter which link I click. What I would like to do is maintain the tab selection and its subcontent on the linked page until I click another tab.

For exampel, starting on the index.shtml page above: When I click the tab "Artiklar, krönikor & debatt" the tab is selected and its subcontent is shown (several links). When I click one of the links in the subcontent I would like the tab selection to maintain status "selected" as that linked page loads.

As it is now, whenever I click a link in a tab's subcontent the tab menu defaults back to selecting the tab on the very left. This is a bit confusing and not very user friendly.

 
At September 19, 2008 8:49 AM , Blogger Danilo Celic said...

@fredrik,

Keeping the selected tab between pages can be handled using the URL Utilities. Take a look at the code on the URL Utilities sample page (look at the very bottom of the page)

You can get to that page from the Spry Samples page, then click Utilities.

Essentially, what you need to do is to add to each link that you want to be able to trigger a specific tab a query string parameter, in the example, it is panel=1, where the number is the index of the tab to show. Remember that JavaScript uses a zero (0) based index, so the first panel is 0, second is 1, etc.

 
At September 20, 2008 12:16 PM , Blogger Fredrik said...

Danilo, thank you for your advice

But I'm not able to make it work. I'm not so good with mathematical logic :). All I get is a broken widget and a graphical mix of the tab 0 subcontent and the content of the tab I would like to get selected.

Go to the page and click tab "Artiklar, krönikor & debatt" and then in the subcontent click link "Digital moral (krönika)" and see what happens.

Maybe I'm confused since I'm not completely sure where on which pages to put the panel=1 reference and the script respectively.

 
At September 21, 2008 5:45 PM , Blogger Danilo Celic said...

fredrik,

Looks like you're not adding the ?panel=x to the query string of your links within the tab content, and it looks like your pages are not including a link to the SpryURLUtils file as described in the URL Utilities sample.

But this isn't a good place to continue with your problem. I'd suggest asking your question in the Spry forums. Before you do, I'd suggest making a demo page that is a copy of Spry URL Utils sample page using the example at the bottom of the page and then trying to fit your content into that example to see how it works.

 
At October 15, 2008 4:41 PM , Blogger Paul said...

Great article - the comments are also very useful. Quick question - I am using the tabbed panels as a horizontal menu, which looks great; I changed the code to use mouseover to change the tab (instead of onclick). The only problem now is, as some users move from the tab to the content, if the mouse moves over another tab that gets activated. Can you think if a simple way to add a delay on the onmouseover/onmouseout to reduce this happening? I think it could be easy, but my java is not up to it...

 
At October 16, 2008 5:46 PM , Blogger Danilo Celic said...

@paul,

What you are looking for should be possible, but I don't have a ready answer for you, so from that score I dont' have a quick fix for you.
If I have some time I'll see if I can work up such a beast, and I'll make a new post about it if I do.

Perhaps you should take a look at the code for the Spry menus as they do have timer code that delays the closing of the sub-menus when you mouse out of them.

Beyond that, checkout the Spry forums someone there may have a ready answer for you.

 
At February 26, 2009 12:50 PM , Blogger wendy said...

I have used your code and it works great, thanks for the article. One question and one problem I am having wondering if you have solution to this. I have a tabbed panel with tabs at bottom on page and I also have or want to have regular spry tabbed panels on the same page. But it does not seem to be working. It appears that the JavaScript I added to top of page to make it work seems to be overriding other tabbed panels JavaScript and breaking the tabbed panels spry with tabs on top.

Have you found a way to have each of these on one page?

 
At March 3, 2009 11:57 PM , Blogger Danilo Celic said...

@wendy,

I made a new post about how to have top and bottom tabs at the same time: Bottom and top Spry tabbed panels on one page

 
At March 8, 2009 1:23 PM , Blogger rkrause said...

I've implemented your fix to move tabs from top to bottom; but i'm running into an issue where the content isn't staying within the box when the content exceeds the height of the box. I tried overflow: auto and overflow: hidden;

but to no avail. Any ideas?

Thanks,
Ryan

 
At March 8, 2009 1:41 PM , Blogger Danilo Celic said...

@Ryan,

There is no height set for the Spry Tabbed panels by default, so I'd assume that you added it yourself. I did a quick test and I had no issue when I set a height to the TabbedPanelsContent class and set an overflow with the following:
.TabbedPanelsContent {
height:100px;
overflow:auto;
}

I saw the scroll bar in top and bottom tabbed panels in my test. For further questions/issues, please make a post in the Spry forum.

 
At March 8, 2009 2:43 PM , Blogger Danilo Celic said...

@Ryan,

Forgot to mention, please post a link to a page that is exhibiting the issue you describe. As is almost always the case, the answer is in the code, show the code in action on a page and it's more likely that a good answer will be arrived at.

 
At March 11, 2009 9:01 PM , Blogger Chris Reardon said...

How can you do this with Collapsible Panels?
I'm trying to move the Tab below the content, and when you click the tab button it 'reveals' the content above it.
-thanks

 
At March 12, 2009 6:45 PM , Blogger Danilo Celic said...

@Chris,

Take a look at the Slide effect

You can place whatever you want to be clicked under the div that's being shown. Take any of the examples from that page, and place the Clickable input button below the DIV that is to be shown, and I think that you'll get close to what you want.

Please note how the example panels show themselves, that is when they are hidden, they reveal themselves from the bottom up. This effect does not handle revealing from the top down.

If you'd like something that does the reveal from top up, please ask in the Spry forums, perhaps someone has a remedy, as I don't know of a way within Spry to do that yet.

 
At April 3, 2009 1:07 PM , Blogger NewPoint Internal said...

thanks man. just what i was looking for!

 
At April 6, 2009 12:31 AM , Blogger Joel said...

Nice tutorial. Just wondering if there is anyway to make the UI return to its' default state on mouseout.

 
At April 8, 2009 9:45 AM , Blogger Danilo Celic said...

@Joel,

There is a Spry tabbed panel sample that shows how to switch tabs change when a tab is moused over:
http://labs.adobe.com/technologies/spry/samples/tabbedpanels/tabbed_panel_sample.htm.

If you're asking about changing tabs back to the default panel when you mouse out, I've not seen such an example, but it would have to account for mousing out but still being over the content area of the tab, otherwise you'll end up with pissed off visitors.

FWIW: If that is what you're trying to do, I think that you're introducing a usability issue, especially for me, as I use the mouse to trigger certain actions and then move it out of the way so that the cursor isn't in the way of me reading the content. If the default panel was constantly showing up when I moved my mouse out of the way to try to read your content, I'd be leaving the site pretty quickly.

However, someone else may have come up with such a solution, try asking about it in the Spry forums

 
At July 13, 2009 8:47 AM , Blogger Macromedios said...

very useful the implementation of this standard widget, works like a charm!

 
At October 9, 2009 4:33 PM , Blogger Janine said...

You are absolutely awesome! Thank you so much for this tip!!!

 
At November 7, 2009 10:22 AM , Blogger James said...

I have 3 Tabbed Panels in my page, and I'd like the third one to have tabs at the bottom.

I can't see how to make the third TP refer to the new javascript I created.

Is it possible to have a separate .js for the third TP?

Oh, and how to do it please!!

 
At November 9, 2009 11:25 PM , Blogger Danilo Celic said...

I think you can do what you're trying to do, but I've not done it, so the following is only what should work, not what I've tried that works.

I'd create a copy of the .js and the .css files. Instead of the CSS and JS changes I say to make to your document, make the changes to the copied files.

In the copied .js file, I'd change all instances of Spry.Widget.TabbedPanels to Spry.Widget.BottomTabbedPanels

I'd then open up the copied .css file and do one of two things:
1. add a class before every style selector in the file such as ".BottomTabs .TabbedPanelsTab"

Then in the page, I'd wrap the bottom tabbed panel with a div that has a class of "BottomTabs" This will allow the "new" selectors in the copied file to apply only to the appropriate tabbed panel. I'd also make sure that the HTML for the tabs are reorganized according to the post.

Next, I'd go to the constructor for the tabbed panel that is to be the bottom tabbed panel, and change it from:

var TabbedPanels3 = new Spry.Widget.TabbedPanels("TabbedPanels3");

to:
var TabbedPanels3 = new Spry.Widget.BottomTabbedPanels("TabbedPanels3");


This should have modified the JS, CSS and the code in the HTML page to allow for top tabbed panels as well as bottom tabbed panels.

I'll think about making a set of files that can be used to create pages with top and bottom tabs.

 
At November 11, 2009 5:05 PM , Blogger Danilo Celic said...

James,

I forgot I had a followup post to this where I describe a method for having top and bottom tabs on the same page, and it's a bit simpler than what I cam eup with off the top of my head:

Bottom and top Spry tabbed panels on one page

 
At December 23, 2009 9:45 AM , Blogger bikeIT said...

Help! I'm about to give up on mouseover on menus that open because the users find it too "twitchy". I've not changed any of the JS other than the onclick to “mouseover”. That "fix" works except that if the user moves the mouse just a hair too fast or near the edge the mouseout occurs or the menu will change tabs or panels. (I've also tried using a Spry accordion with hopes of preventing the dreaded twitchiness - with no success).
I've search the Adobe forums and even paid for a menu which was a waste of money. I like Spry just fine but I cannot find any solution to delay the mouseover, but I find many asking for the same help. Any help much appreciated.

 
At December 30, 2009 4:06 PM , Blogger Danilo Celic said...

The tabbed panels, accordion panels and Spry menus aren't designed to handle any type of delay if you modify them to use mouse over event. That's why they do exactly what yo tell them to show when they are moused over this so called "twitchiness".

You'd have to program the delay in yourself, and figure out how much delay and when to actually show the content keeping track of when the user moves over to another tab/panel or out of the widget completely. Not an easy task to accomplish when the widget wasn't designed to do that in the first place.

There may be some widgets out there that do what you want, perhaps the :
jQuery UI tabbed panel which has mouse over as an option.

 

Post a Comment

Links to this post:

Create a Link

<< Home