How to Solve the Problem
Recreating this effect is simple to do if you know what plugins to use. There are plugins out in the wild already, but we want our jQuery to satisfy the following requirements:
- Degrades perfectly without JavaScript enabled
- Sliding panels effect without hogging browser CPU
- Next and previous buttons added using JavaScript because they hold no use without JavaScript
- Hitting the page with a specific hash (i.e. page.html#preview) shows the right tab, and highlights the right navigation
- Any link on the page that refers back to a panel should trigger the effect and highlight the right navigation – this should happen without any extra work
The hash is the emphasised part (including the # symbol) in: http://jqueryfordesigners.com/page.html#example
In fact, our version of this slider will be better than Panic’s and the current jQuery plugins if we can meet all of the requirements.
For example, in the Panic example linking directly to the preview pane doesn’t correctly highlight the navigation.
This whole solution is going to rely heavily on Ariel Flesler’s scrollTo plugin and particularly it’s ‘adapters’ to enhance the power of the scrollTo plugin.
I’ve provided a screencast to walk through how create this functionality. Details on how and what I used can be found below.
Watch the coda slider effect screencast (alternative flash version)
QuickTime version is approx. 90Mb, flash version is streaming – I’ve also noticed the sound is slightly over to the left – I’ll fix that for next time!)
View the demo and source code used in the screencast
Plugins Required
Along with jQuery we’ll need the following plugins – I recommend using the minified versions for production, and perhaps even development (download links can be found at the bottom of the linked pages):
Markup
Requirement 1: degrades perfectly without JavaScript enabled
To ensure this works without JavaScript, we will use the CSS overflow property to control the effect.
This way our panels will still focus in to view if a user clicks, or if the URL refers to a specific panel.
HTML
It’s worth noting that although we could scroll the individual panels inside a single nested DIV, for the JavaScript to make the effect work, it will be a nested DIV that will scroll – not the individual panels. You can see this in the markup below:
<div id="slider">
<ul class="navigation">
<li><a href="#sites">Sites</a></li>
<li><a href="#files">Files</a></li>
<li><a href="#editor">Editor</a></li>
<li><a href="#preview">Preview</a></li>
<li><a href="#css">CSS</a></li>
<li><a href="#terminal">Terminal</a></li>
<li><a href="#books">Books</a></li>
</ul>
<!-- element with overflow applied -->
<div class="scroll">
<!-- the element that will be scrolled during the effect -->
<div class="scrollContainer">
<!-- our individual panels -->
<div class="panel" id="sites"> ... </div>
<div class="panel" id="files"> ... </div>
<div class="panel" id="editor"> ... </div>
<div class="panel" id="preview"> ... </div>
<div class="panel" id="css"> ... </div>
<div class="panel" id="terminal"> ... </div>
<div class="panel" id="books"> ... </div>
</div>
</div>
</div>
That’s it. Without CSS this markup works perfectly for our content, almost exactly the way tabs work without JavaScript and CSS.
CSS
I won’t detail all the CSS like the navigation or shading effects – just the CSS required to correctly create the effect.
#slider {
width: 620px;
margin: 0 auto;
position: relative;
}
.scroll {
height: 250px;
overflow: auto;
position: relative; /* fix for IE to respect overflow */
clear: left;
background: #FFFFFF url(images/content_pane-gradient.gif) repeat-x scroll left bottom;
}
.scrollContainer div.panel {
padding: 20px;
height: 210px;
width: 580px; /* change to 560px if not using JS to remove rh.scroll */
}
Note also that I’m choosing to use overflow: auto; – this way, if the user does have JavaScript disabled, there will be a visual que that the panels can be scrolled. If you want to remove the horizontal scroll in IE, I would recommend changing .scrollContainer div.panel‘s width to 560px to account for the right hand scrollbar.
I also plan to include scrolling buttons to go left and right. Although the elements will be created by the JavaScript, we’ll still need the CSS to place the buttons in the right place. Our JavaScript will put the buttons before and after the outer div.scroll element. We have to use absolute positioning to place them, so this is why #slider has position: relative; applied:
.scrollButtons {
position: absolute;
top: 150px;
cursor: pointer;
}
.scrollButtons.left {
left: -20px;
}
.scrollButtons.right {
right: -20px;
}
jQuery
Requirement 2: Sliding panels effect without hogging browser CPU
If you try this effect using CSS, to use positioning to move the panels around it will eat up your CPU, and the browser will no likely lock up. This is why we’re using Ariel’s scrollTo pluing. The scrollTo plugin literally scrolls the element via it’s overflow (or can be used to scroll the actual window).
Required Plugins
<script src="jquery-1.2.6.min.js" type="text/javascript"></script>
<script src="jquery.scrollTo-1.3.3-min.js" type="text/javascript"></script>
<script src="jquery.localscroll-1.2.5-min.js" type="text/javascript"></script>
<script src="jquery.serialScroll-1.2.1-min.js" type="text/javascript"></script>
Next and Previous Buttons
Requirement 3: Back and forward buttons added
This is easy vanilla jQuery, here’s the snippet from the final code:
var $scroll = $('#slider .scroll');
$scroll
.before('<img class="scrollButtons left" src="images/scroll_left.png" />')
.after('<img class="scrollButtons right" src="images/scroll_right.png" />');
Note the classes I’ve applied the scrollButtons to the images so they’ll be positioned properly.
Navigation Updates Automatically
Requirement 4: Hitting the page with a specific hash highlights the right navigation
This is one of the key features that I felt was important to the slider. If I navigated to a specific panel, the navigation should match.
This is achieved using event binding. When the scroll plugin completes it’s effect, it will call our trigger function.
The trigger function will receive the ID of the element it has just shown, and search for the navigation item whose href’s hash matches the ID.
For example, if the div#sites element is shown, the ID ‘sites’ is sent to our trigger. Our trigger function will now look for links in the navigation that end with ‘#sites’: <a href="#sites">Sites</a>.
This trigger function will be attached to the onAfter property in the scroll options and called when the page loads for the first time with a hash in the URL.
// bind the navigation clicks to update the selected nav:
$('#slider .navigation').find('a').click(selectNav);
// handle nav selection - lots of nice chaining :-)
function selectNav() {
$(this)
.parents('ul:first') // find the first UL parent
.find('a') // find all the A elements
.removeClass('selected') // remove from all
.end() // go back to all A elements
.end() // go back to 'this' element
.addClass('selected');
}
function trigger(data) {
// within the .navigation element, find the A element
// whose href ends with ID ($= is ends with)
var el = $('#slider .navigation').find('a[href$="' + data.id + '"]').get(0);
// we're passing the actual element, and not the jQuery instance.
selectNav.call(el);
}
I’ve had to separate out the selectNav function because it also be called when the user clicks on the navigation links.
To complete this requirement, once the page is loaded, we need to check whether there is a hash on the URL, and if so, trigger the ‘scrollerComplete’ function:
if (window.location.hash) {
trigger({ id : window.location.hash.substr(1)});
} else {
$('#slider .navigation a:first').click();
}
By default, we’re triggering a click to the first navigation item if there’s no hash on the URL.
Any Link Triggers Effect
Requirement 5: Any link on the page that refers back to a panel should trigger the effect
Since we’re all lazy developers, we don’t want to have to specifically markup arbitrary links on the page that should trigger this effect.
This is where Ariel’s localScroll plugin comes to the rescue. By just applying that plugin with our default settings any link on the page will trigger the effect. In addition, because we’re going to trigger our ‘scrollerComplete’ function when the effect has finished, it will correctly select the navigation associated.
The jQuery Code
Here’s the code with all the above requirements added in. The code is commented to explain what we’re doing.
I’ve also decided to include a bonus requirement – to support both horizontal or vertical scrolling.
// when the DOM is ready...
$(document).ready(function () {
var $panels = $('#slider .scrollContainer > div');
var $container = $('#slider .scrollContainer');
// if false, we'll float all the panels left and fix the width
// of the container
var horizontal = true;
// float the panels left if we're going horizontal
if (horizontal) {
$panels.css({
'float' : 'left',
'position' : 'relative' // IE fix to ensure overflow is hidden
});
// calculate a new width for the container (so it holds all panels)
$container.css('width', $panels[0].offsetWidth * $panels.length);
}
// collect the scroll object, at the same time apply the hidden overflow
// to remove the default scrollbars that will appear
var $scroll = $('#slider .scroll').css('overflow', 'hidden');
// apply our left + right buttons
$scroll
.before('<img class="scrollButtons left" src="images/scroll_left.png" />')
.after('<img class="scrollButtons right" src="images/scroll_right.png" />');
// handle nav selection
function selectNav() {
$(this)
.parents('ul:first')
.find('a')
.removeClass('selected')
.end()
.end()
.addClass('selected');
}
$('#slider .navigation').find('a').click(selectNav);
// go find the navigation link that has this target and select the nav
function trigger(data) {
var el = $('#slider .navigation').find('a[href$="' + data.id + '"]').get(0);
selectNav.call(el);
}
if (window.location.hash) {
trigger({ id : window.location.hash.substr(1) });
} else {
$('ul.navigation a:first').click();
}
// offset is used to move to *exactly* the right place, since I'm using
// padding on my example, I need to subtract the amount of padding to
// the offset. Try removing this to get a good idea of the effect
var offset = parseInt((horizontal ?
$container.css('paddingTop') :
$container.css('paddingLeft'))
|| 0) * -1;
var scrollOptions = {
target: $scroll, // the element that has the overflow
// can be a selector which will be relative to the target
items: $panels,
navigation: '.navigation a',
// selectors are NOT relative to document, i.e. make sure they're unique
prev: 'img.left',
next: 'img.right',
// allow the scroll effect to run both directions
axis: 'xy',
onAfter: trigger, // our final callback
offset: offset,
// duration of the sliding effect
duration: 500,
// easing - can be used with the easing plugin:
// http://gsgd.co.uk/sandbox/jquery/easing/
easing: 'swing'
};
// apply serialScroll to the slider - we chose this plugin because it
// supports// the indexed next and previous scroll along with hooking
// in to our navigation.
$('#slider').serialScroll(scrollOptions);
// now apply localScroll to hook any other arbitrary links to trigger
// the effect
$.localScroll(scrollOptions);
// finally, if the URL has a hash, move the slider in to position,
// setting the duration to 1 because I don't want it to scroll in the
// very first page load. We don't always need this, but it ensures
// the positioning is absolutely spot on when the pages loads.
scrollOptions.duration = 1;
$.localScroll.hash(scrollOptions);
});
Wrap UP
That’s everything you need for the perfect slider. Ariel has lots of other examples of how the scroll plugins can be used on his web site so do check them out.
I’ll also be posting a follow up to last month’s survey.
If anyone has any questions, suggestions or better examples, please do share by dropping a comment on the site.
You should follow me on Twitter here I tweet about jQuery amongst the usual tweet-splurges!
Related screencasts
Demo
If you find this demo doesn't work as expected, it's possibly due to the demo running from within an iframe. Try running the demo in it's own window.
Source Code

Play QuickTime version
Play Flash version

Remy On 12th June 2008 at 08:06
@Derek – cheers – now fixed.
joe On 12th June 2008 at 15:06
To implement 2 or more sliders on one page (the long way) is to create another function. I just copied this: jQuery.fn.codaSlider = function(settings) {… and created jQuery.fn.codaSlider2 = function(settings) {…
On my html page, i called: jQuery(window).bind(“load”, function() { jQuery(“div#slider1b”).codaSlider2() });
Also had to duplicate the CSS and basically named everything panel2, wrapper2, slider2, etc…
Messy but i was able to make it work.
Remy On 12th June 2008 at 16:06
@Jasper + Joe – I’m actually working on the plugin and handling multiple versions on the page. I’m speaking to Ariel (the author of the core plugins) to get it to work. Once it’s all there, I’ll release the new plugin.
Thanks!
Raymond On 12th June 2008 at 22:06
Hi im using the javascripts from jqueryfordesigners.com/demo/coda-slider.htm and putted the html divs as showed on that page within a table, now i cant seem to get it working… all i get is Error: $panels.css is not a function
Im sure its something i forgot or doesnt it work within an table?
Further it looks awsome the working demo! thanks for making it available
Raymond On 12th June 2008 at 22:06
nevermind my last post, it works well , the error message only comes up when logged in to the MODx manager (CMS) and having the QUICKEDIT visable on the visitors page where the scroll pane is shown. it works fine in IE6.0, IE7.0 and FF2 (just cant get it working in Safari on windows) but thats not a problem ;)
Thanks!
Raymond On 12th June 2008 at 22:06
Hi nevermind my last comment, i only got the error because somehow the QUICKEDIT is interupting the scroll pane script. this happens when logged in to MODx manager (CMS) and having the QUICKEDIT turned on at the visitors page where the scroll pane is show.
It works very good in IE6.0, 7.0 and FF2 just somehow it will not work in Safari windows but thats not a problem for me ;)
Thanks
Ariel Flesler On 12th June 2008 at 23:06
Great article.
I know you’re a busy guy lately but… What are you waiting for, to update the article with the code we made, huh ? :D
Cheers Remy
Chris Mahon On 13th June 2008 at 09:06
Remy,
Is it possible to apply this effect to something like a submit button? I.E. I want to specify which “panel” to scroll to if an submit button is clicked.
I know how to attach a click to the button, but not so sure which part of the slider JS to then call?
Cheers, Chris
Remy On 13th June 2008 at 14:06
@Raymond – if you still have that error, open up Firebug and find out what’s in $panels. I think you’ll find it’s not a jQuery object. You’ll need to tweak the coda slider code – if you add
debuggerjust before that line, Firebug will break allowing you to take a look.@Ariel – It’s currently breaking with more than one on the page. I’ll catch up with you to get it sorted for all these nice people :-)
@Chris – quick hack answer (as I need to double check with Ariel) is
$('a[href$="' + IDSELECTOR + '"]).trigger('click');– but you’ll need to test that!Michael B On 16th June 2008 at 02:06
I’m using this in a jsp…and the nav images are seriously out of wack (images are hugggge!). I tried added height and width in the js and it didn’t work. Any suggestions?
Hans Engel On 16th June 2008 at 20:06
Hi, I’ve just implemented this slider into my site, but I’ve found a bug (perhaps just with my current browser, which is Firefox 3).
If you visit the page using a hash at the end (ex. example.html#something) the slider will display the section called ‘something’, but the navigation link for ‘something’ will not be highlighted — the first section’s link will remain highlighted.
This isn’t too important for my purposes, but I figured it’d be better if you and the public were aware of this bug.
Thanks, Hans Engel
Graham T On 17th June 2008 at 12:06
This is just what I was looking for! Nice simple and relatively clean. Fantastic stuff
I’ve recently discovered the joys of JQuery and I especially like the way it integrates nicely with ASP.Net without too many headaches. Your coda slider is now firmly embedded on our site at http://www.silver-pride.com :)
Cheers and thanks again
Graham
Graham T On 18th June 2008 at 15:06
One thing I did notice was that there is an outline around the anchor links in Firefox. This is an “accessibility” feature apparently. However, it can be removed easily by adding this to the CSS.
a { outline: 0; }
Cheers
Graham
Simon On 19th June 2008 at 21:06
Really nice!! But it doesn’t change the url with the anker like the default scroll of Ariel Flesler does. I added this line in the trigger function to enable this: window.location = “#”+data.id;
greetz
Graham T On 20th June 2008 at 11:06
aha, it does now! Thanks for that.
Sorpigal On 23rd June 2008 at 12:06
The Firefox bug some people are reporting is not a bug.
In Firefox if you open the page with no hash in the URL then type a hash after the URL and hit enter the navigation link does not change to the correct tab and no scroll effect is shown, but the correct content does appear. This is because typing in the URL bar does not trigger a page reload and is not an anchor to which some events can be attached. Firefox is simply jumping to the anchor as requested. In the real world this is not a problem because users do not type anchors into the address bar.
Tosho On 23rd June 2008 at 13:06
Hi, great tutorial , but I’ve got a question : is it possible to add fadeIn and fadeOut effects for the panels where tey come in and come out – it will looks nicer.
Master On 24th June 2008 at 21:06
Hey, with all the people asking for more I just wanted to say thanks, this is by itself great. It’s just a very nice way to show the flow of development using jQuery, Firebug and a simple texteditor. Thanks for your work!
Charles On 25th June 2008 at 01:06
Nice tutorial. This is much smoother than the previous coda-slider thing I was using on another site. But I’m having the same problem that I had before in that when I break the navigation away from the slider, I can’t use the ‘selected’ state on my nav. This is probably very simple, but I’m php/javascript ignorant so I can’t figure out where I’ve broken it or how to fix it. you can have a look here: http://www.oneprcnt.com/1prcnt/index.html
If anyone knows a solution I would be eternally grateful.
Tangier Clarke On 26th June 2008 at 16:06
I am trying to implement this and having these problems and questions:
when I put a large amount in one of the panes that would cause the div to be larger than it’s height, no vertical scroll bar shows up and my text is cut off on the right side of the pane.
navigation links don’t seem to work if I am not using a “ul” tag. Is this possible? I am not interested in the tab bar, but want to create my own links that control the slider.
Is there a way to make the individual panels grow or expand as needed? I’v seen a slider do this with text, but can’t find the example.
Charles On 27th June 2008 at 18:06
Here’s another issue: I can’t get Lightbox to work within the slider. This is most likely a conflict of frameworks. Fine. But shouldn’t I be able to use Thickbox, since it uses JQuery?
Mennoramon On 1st July 2008 at 09:07
I’m trying to combine this beautiful slider with sIFR navigation. But everytime i click a tab the whole rendering of the navigation starts all over , making the beautiful sliding effect dissapear.
Can anyone help me with this?
My test version: http://www.mennoschmitz.com/test/coda-slider.html
menno
Aamir Afridi On 3rd July 2008 at 16:07
This plugin is wounderful but it got a bug.
Just navigate to any tab and refresh the page. You will get mix of different tab’s data.(try yourself to see what i mean)
It will be nice to use cookies to save the active tab id etc, so that the reload of the page can bring the same tab or at least the first tab nicely.
I am working on it to fix it. Will post if i found something.
By the way i am using Firefox 2.0 / Firefox 3
David On 4th July 2008 at 10:07
Great tut, but I’m getting following error
parse error, unexpected ‘(‘, expecting T_VARIABLE or ‘$’
for the line
$(‘#slider .navigation’).find(‘a’).click(selectNav);
someone can help? cheers, david
Remy On 4th July 2008 at 11:07
@David – I think you need to validate your PHP running the page. It’s nothing to do with the JS.