Tab Navigation with Smooth Horizontal Sliding Using jQuery
read 62 commentsIn this tutorial I'll show you how to create a navigation menu that slides horizontally. It begins with a set of "tabs" on the right side of a containing element. When clicked, a tab slides to the left to reveal a group of links. Click the tab again, and it slides back. While I've never had a need to build one of these for any of my own projects, quite a few people have asked if I would demonstrate how it might be done, so here goes.
Download
You can now download a .zip of complete, working demos featured in this post.
The Styles
For the navigation items, I used a simple unordered list wrapped in a <div class="nav">. While the HTML structure is straightforward, the CSS is a little tricky, so I'll detail it here:
- /* nav wrapper */
- .tab-nav {
- position: relative;
- width: 610px;
- overflow: hidden;
- background: #ddd url(tab-slide.png) no-repeat 0 0;
- }
- /* nav */
- .tab-nav ul {
- position: relative;
- float: left;
- width: 1600px;
- margin-left: 535px;
- padding-left: 0;
- list-style-type: none;
- background-color: #fff;
- }
- .tab-nav li {
- float: left;
- clear: left;
- }
- .tab-nav a {
- display: block;
- width: 74px;
- border-right: 1px solid #ddd;
- height: 25px;
- line-height: 24px;
- float: left;
- text-align: center;
- text-decoration: none;
- color: #000;
- background: url(tab-slide.png) no-repeat 2px -194px;
- }
- .tab-nav a.expanded {
- background-position: 2px -244px;
- }
- /* second-level overrides */
- .tab-nav ul ul {
- float: left;
- background-color: #333;
- width: auto;
- margin-left: 0;
- }
- .tab-nav li li {clear: none;}
- .tab-nav li li a { color: #fff; width: 100px; background-image: none;}
Most of the relevant CSS here has to do with positioning the nav items. I set the top <ul>'s left margin to 75 pixels less than the wrapper's width so that the top-level links appear on the right side. The 1600px width for the <ul> gives the floated list items ample room to line up horizontally next to each other.
The wrapper's overflow declaration is significant, as it hides the list items when they're sticking out to the right, but the rest is "window dressing."
Sliding the Nav
With the nav looking the way I want it at its initial state, it's time to make it do something. I'll start with a simple setup, having each "tab" (top-level item) slide to the left on the first click to reveal its sub-nav items, and slide back to its initial position when it's clicked a second time.
For this basic behavior, everything can be done inside a click handler for the top-level links. Note: Since I'm using multiple navs for this tutorial, each with its own set of behavior, I'll be referring to them by ID, unlike in the CSS snippet above, where everything is styled by class. There is nothing special about the selectors or their naming here. Name your own elements and select them however you want.
The first thing to do is set a few variables. The $parentItem variable is the <li> parent of the clicked link. The slideAmt is the width of the nested <ul>, which is the next sibling of the link. And direction will eventually determine whether the parent <li> should be slid to the left or to the right.
Notice the use of $(this). Inside the click handler, this refers to the clicked DOM element. By wrapping this in $(), we can call jQuery methods on it.
To get the sliding motion to occur, we can animate either the left property or the marginLeft property. Here, I'll animate marginLeft. So, the next thing to do is determine the direction of the animation based on the current value of marginLeft: If it's less than 0, direction is set to "+=", which increases it (back to 0); otherwise, direction is set to "-=". At the same time, an "expanded" class will be toggled so that the arrow background image can change directions.
- var $topLinks1 = $('#tab-nav-1 > ul > li > a');
- direction;
- direction = '+=';
- } else {
- direction = '-=';
- }
- // code continues
- });
Finally, we do the animation, plugging in the direction and slideAmt variables. The return false; line stops the default click action from occurring. Here is the finished code for the basic implementation:
- var $topLinks1 = $('#tab-nav-1 > ul > li > a');
- direction;
- direction = '+=';
- } else {
- direction = '-=';
- }
- $parentItem
- return false;
- });
Give it a try:
One at a Time
That's all well and good, but I don't really care for having more than one row of items expanded at a time. A couple simple modifications will fix that for us:
- var $topLinks2 = $('#tab-nav-2 > ul > li > a');
- direction;
- direction = '+=';
- } else {
- direction = '-=';
- }
- $parentItem
- return false;
- });
- });
The links are stored in a variable first thing here. Whenever a link is clicked, all links have the "expanded" class removed. Of course, only one, at most, will have that class, but I'm lazy and it's easier to tell all of the links to remove the class than it is to hunt links that have the class first.
The same check is performed to set the direction of the animation. If the clicked link's parent <li> is going to be slid to the left, the link will also get the "expanded" class.
Finally, the clicked link's parent is animated in the direction and number of pixels specified by the variables. But here's the twist: all of that parent's siblings have their marginLeft property animated to 0. Again, I'm taking the lazy route, animating all of the siblings, even though one or none of them will need it.
Here's a demo of the "one at a time" version:
Auto-Collapse
Now that the expanding and collapsing are happening the way I like it, I'll add one more little touch. If the user's mouse leaves the containing <div class="tab-nav">, and stays out for a full second, any expanded list will collapse.
- var closeAll,
- $topLinks3 = $('#tab-nav-3 > ul > li > a');
- direction;
- direction = '+=';
- } else {
- direction = '-=';
- }
- $parentItem
- return false;
- });
- $('#tab-nav-3')
- closeAll = setTimeout(function() {
- }, 1000);
- })
- clearTimeout(closeAll);
- })
- });
Line 2 declares a variable that will be used for the setTimeout(), which you can see tucked inside the .mouseleave() method near the bottom of the code. The setTimeout() function has two arguments: the first is an anonymous function that contains code for triggering the collapse of the list items, and the second is the number of milliseconds to wait (1,000 milliseconds) before the first argument (the anonymous function) is executed. The clearTimeout() inside the .mouseenter() method does what its name suggests: it clears the timeout. If the user mouses out of the nav area but then mouses back in before the 1000 milliseconds are up, the timer is stopped and the function will not be executed.
Note: The mouseenter(fn) and mouseleave(fn) shorthand methods are available as of jQuery 1.3. If you're still using jQuery 1.2.6, you can use .bind('mouseenter', fn) and .bind('mouseleave', fn) instead. Or, with just about any version of jQuery, you can use .hover(fn, fn).
Here is the final demo:
There are many ways to do this sort of thing. Just tweak the CSS or change the animation for a completely different experience.
















Impressive! Thanks for sharing.
There is any download link to download the full working example ?
Overall, looks great. Gets a little wonky when you tab through the links. At first I thought this was designed to handle tab/keyboard navigation. Until I tabbed through them all, and then clicked on the 'opener'. Then it really goes nuts.
Jason,
Wow, thanks for catching that! Looks like I have something to work on for my next post.
Hey again. I just put some code in the last demo above to set the
tabIndexproperty. Not the least obtrusive way to do it, but it works. I'll write something up later.what a work really nice job done, nice jquery plugin good job.
Very nice.
Check IE 7 compatibility though - tabs are always visible.
When will I ever learn? Okay, will check it out as soon as possible. Thanks for the alert.
All good now in IE7 now. Just had to add
position:relative;to the.tav-navclass. Keyboard navigation is still wonky in IE, though. That's next on the to-do list. Thanks again.I don't think I've ever run across navigation that works this way; I like it! It's another example of doing something that's pretty easy in jQuery but creates a very fresh effect.
I wished you would publish the full source code, not only the js files. For example I don't see how you manipulate the left and right arrow heads for each of the major list items.
Hi William,
As I mention in the entry ("At the same time, an 'expanded' class will be toggled so that the arrow background image can change directions"), the manipulation of the arrow heads is simply done by adding the "expanded" class to the major list items. The arrow heads are in an image sprite. Adding the class changes the background position. I showed all of the CSS (and commented on some of it) in the first code block above. In any case, here is the relevant CSS for switching the direction of the arrows:
Here is the image sprite.
Thank you for you kind response. I really appreciate your tutoring. I will study your work later today when I can spend some time to look at what I don't understand. Take care and once again thanks for your attention.
WBR
It seems that the problem is IE8. The same code works in Chrome but fails to produce the right pointing arrow in IE8.
Thanks!
WBR
interesting functions, a new model of navigation tabs. thanks
Where is the download link to download the full working example :-(
its really wonderful, I am working on a Arabic website and now I can use this one for menu, never thought to do something like this.
That's awesome horizontal sliding navigation. I love it, and I will be perfect if you set no outline for the link. Good job!
Cool,Awesome thnx man
excellent! perhaps i'm gonna using in my next project
thanks for sahre this kind of resources !
Muito bom essa aplicação em JQuery
Very good this aplication in JQuery
vou até adicionar isso no meu site hihihi
I going add this into my site hihihi
Cool menu.
Integrating with blogger I've run into a hitch, the mouse enter event wasn't bound to the tab-nav id:
so I've added and it looks like this:
I understand that this would happen in a normal context, also I didn't test it yet...
Alberto,
You actually caught a little bug in the entry's formatted code. Although the source code is correct, the code I posted in the entry had an extraneous semicolon. You can either add
$('#tab-nav-3')to the.mouseenter()line, as you did, or remove the semicolon from the previous line (and rely on chaining). I chose to remove the semicolon.Cheers!
Hi Karl, Great work. one question tough, is it possible to have the menu on the left, with submenu sliding to the right ? I've tried, but didn't get it to work. And another question, is it possible to have the submenu already open and highlighted when arriving on a page ?? thanks a lot
I'am newbie, would u share the HTML for this tutorial ?
tnx b4
Very informative article.I learn more from this site.Thank you.
interesting functions, a new model of navigation tabs. thanks
It's nice you guys have attached the .js file..but for us total n00bs with JQuery can you guys also post or upload the HTML so we can see how all of this works. I'm very interested in learning JQuery and pulled down the .js file..but any possibility you guys can upload the entire HTML or what calls the JS?
Hi Jon,
I just zipped up complete, working demos featured in this post. Hope that helps.
I'm very interested in learning JQuery and pulled down the .js file..but any possibility you guys can upload the entire HTML or what calls the JS?
You can now download a .zip of complete, working demos featured in this post.
If you take a look at this link Click here If you look at the three slightly different colored tabs, I am trying to use jquery ui with these tabs. I want the hover effect to work on these tabs so that when I hover over each tab, new information is displayed. I know that jquery ui tabs widget can do this. To be quite honest though, I have no idea where to start to learn how to customize this widget to the size that I want it to be. I am new to javascript, so I was wondering if there is a website where it will somewhat walk me through this process?
Thanks for any help.
Hi David,
You could post the question to the jquery-ui Google Group. They should be able to help you out.
I think i would like to try this great menu in my blog. Thanks
thank for tutorial
Am trying to get something like this, so far not working any hint? Thanks
Better would be for the button to remain in place while the links expanded out from the button. This would keep the user from having to move the mouse to collapse the links themselves.
Good idea!
Hi all,
First of all, thanks for sharing Karl, it's a very valuable ressource for jquery beginners.
I'm looking for the same setup as Doug, any idea how to implement that ?
cheers
hi, ive been looking for something like this to use for my blog (blogger). is there a way that i can use this for blogger? what will the codes look like? this is a very wonderful widget.
This script is great! -
Is there a Version of this where the Menu is on the LEFT SIDE?
I've been tweaking the code, but it's just not right... If anyone, or the author has this in an opposite side version - that would really be fantastic!
Is very nice ...
But IE6 browser is not working...
Please help me..
Hey Karl,
I'm definitely bookmarking this, I know I will need this one day. Very, very nice! Thanks for all your time and for sharing it! :)
Totally off topic, but I also have a WordPress blog and would like to know if that is a WordPress plugin that creates the 'author' tag on your posts? Please share if so, that's nice, too!
Tracy
Hi Tracy,
Actually, it's just the
comment_class()WordPress function that I added to my comments.php file. It looks something like this in the template:Once you have that in there, comments from the post's author get a "bypostauthor" class. You can use CSS to style it however you want. I just used a background image.
Hope that helps lead you in the right direction.
It's superb post as in these days I am searching for similar effect's tut for my project.
Thanks
using keyboard tab and triggering the navigation via enter shows interesting results, this could be optimized :)
Hy
Great job o the tutorial but I have a question.
My question is like this insted of moving the expanded class can`t I just change the state of it , what I mean is that I don`t need the nested sub menus and I just want to change the picture if the link is clicked, how can I do this ?
Thx and excuse my english
nice jquery plugin good job dude.
also check on IE7 .
Has anyone been able to get this to slide to the right instead of the left? I've been trying, but am not getting anywhere...
-Thanks.
This menu doesn't work in ie6... How to fix it?
How to get this to slide to the right instead of the left?
Hi, great plug in and very easy to implent, I just have one question, I used on a project, and I tested on three different browsers, on Safari and Firefox it works great, but when I tried it on IExplorer as soon as I click the arrow it expands horizontally but the arrow dissapears make it impossible to close, any idea on why is this happening ??
Hard to know without seeing it. Does the same problem occur on this entry's example above? Which version of IExplorer did you test?
Nice menu. Is to possible to slide above instead of side..
Hi Karl,
Really good job. Can you suggest some idea so that I can have horizontal parent tab with same features.
Thanks
Nice script, thank you! I'm the fourth, and hopefully the last user to ask: what must we do in order to make the menu slide from left to right? It has been asked many times but there is no answer yet. Of course, you are not obliged to answer as you already did a lot, but it will really be nice of you.
I tried to change the "direction" and the "marginLeft" in the js file but with no success...
Hope this help...
CSS:
Javasript:
Awesome menu! Thank you for posting. I was wondering how to make this menu function so it slides out on hover instead of click. I am using the left to right version of the JS/CSS posted by Phet.
Thanks!
This is really nice, however there's a huge problem.
Let's say I have a centered page and I want to use this menu on the right-hand side so that the items slide in over the content (pretty much as per your example).
The positioning of the containers means that any hyperlink in the content can't be clicked - even all the containers of the nav have a transparent background.
Anyone know of a solution to this?
Had the same issue. I referred to another Tut that Karl wrote : http://www.learningjquery.com/2009/02/slide-elements-in-different-directions
BUT, I only have a 1 row menu.
You can see it here : http://www.prohockeylife.com/media
Hop this help!
Phet
Hi,
Thanks for this example. Could you please tell me if you have an idea on how to do a content tab slider. So, in your example, instead of having a list of submenus sliding can I have a small post-it size window that slides and shows link or information etc.
Thank you very much.
this one works very nice: http://codecanyon.net/item/the-fusion-of-tabs-and-slider-with-jquery/3785796