From our sponsor: Ready to show your plugin skills? Enter the Penpot Plugins Contest (Nov 15-Dec 15) to win cash prizes!
Today we want to share a slick and flexible vertical jQuery accordion with you. The main idea is to expand the accordion slices on click and show some more information. The other slices will become less opaque and squeezed. When navigating to the next slice using one navigation arrows, a new slice will slide in from the top or the bottom. Once a slice is open and we navigate, the subsequent slice will open on slide.
The beautiful portrait photography is by Images by Alan Turkus. Check out his Flickr Photostream. The images are licensed under the Creative Commons Attribution 2.0 Generic (CC BY 2.0) License.
We also use the jQuery Mousewheel Plugin by Brandon Aaron which allows us to navigate through the accordion using the mouse wheel.
The options for this plugin allow to customize the height and width, the number of slices visible, the height of an expanded slice and others. Let’s first see some examples before we explain each option.
Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.
Examples
Take a look at all the examples (you can also navigate from them to all the other demos):
- 3 visible slices / Default
- With easing
- 5 visible Slices and higher transparency
- 2 visible slices and slower animation
- Fullscreen example
For the HTML structure we have the accordion container, the navigation spans and the wrapper with the slices:
<div id="va-accordion" class="va-container"> <div class="va-nav"> <span class="va-nav-prev">Previous</span> <span class="va-nav-next">Next</span> </div> <div class="va-wrapper"> <div class="va-slice va-slice-1"> <h3 class="va-title">Marketing</h3> <div class="va-content"> <p>Henry Watson</p> <ul> <li><a href="#">About</a></li> <li><a href="#">Portfolio</a></li> <li><a href="#">Contact</a></li> </ul> </div> </div> <div class="va-slice va-slice-2"> ... </div> </div> </div>
We give each slice a different class to define a background image for them. In the last fullscreen example we have color classes to assign a different background color to each slice.
Let’s take a look at the example with just 2 slices and a slower animation speed:
$('#va-accordion').vaccordion({ expandedHeight : 350, animSpeed : 400, animOpacity : 0.7, visibleSlices : 2 });
The following options are available:
// the accordion's width accordionW : 1000, // the accordion's height accordionH : 450, // number of visible slices visibleSlices : 3, // the height of a opened slice // should not be more than accordionH expandedHeight : 350, // speed when opening / closing a slice animSpeed : 250, // easing when opening / closing a slice animEasing : 'jswing', // opacity value for the collapsed slices animOpacity : 0.2, // time to fade in the slice's content contentAnimSpeed: 900, // if this is set to false, // we collapse any opened slice // before sliding savePositions : true
If you, for example, would like to show a slice fully on expansion, using the whole height of the accordion container, then you set the expandedHeight to the same value like the accordionH (the height of the accordion). In our last example we used the full window width and height and also adjusted some style (see inline style in the example) in order to remove any margins:
$('#va-accordion').vaccordion({ accordionW : $(window).width(), accordionH : $(window).height(), visibleSlices : 5, expandedHeight : 450, animOpacity : 0.1, contentAnimSpeed: 100 });
We hope you like this accordion and find it useful!
@Mike,
I was able to stop event propagation for links within div.va-slice by adding the following on line 414 of Mary’s code:
$(‘div.va-slice a’).click(function(event) {
event.stopPropagation();
});
@ Eric.
Thanks… I also wanted to make such a change as mike. You helped me 😀
Awesome… I’m Lovin It 🙂
hi,
how to be the first to open the slides?
how can i change that to disable the clickfunktion in the content area….i wanna click inside my opened content area..but it always closes, by clicking in the content area.
can somebody help me?
For some reason when I embed it as an XML gadget there are blank slices 2,4,6,8 and slices 1,3,5,7 are organized 1,2,3,4.
So it appears – 1, blank, 2, blank, 3, blank…
It appears fine when testing the html document.
Any solution to this problem?
This is lovely but unfortunately does not work in IE8 and below rendering the plugin mostly useless.
I doubt this will be fixed any time soon since the issue has already been raised 3 times. Real shame
Above comment only applicable to example 2 (with easing)
I suppose I can settle for example 1
@Aaron
Is there any way to have one of the slides in the open state?
I’m also interested into solving this problem, anyone? I’ve customized example5 for my needs, now the only thing left is the open tab on load. I would really appreciate some help.
Outstanding work Mary Lou!
So I put a thumbnail image in the first slice that clicks to a larger image using fancy box. The fancy box larger image comes up but at the same time the slider div closes that It was in. I want this to stay open. It does the same thing in the demo when you click on a link instead a slice. Basically I want clicking on the H3 title to be what opens and closes each slice. Is this possible? and how would I do it?
Please advise,
thank you,
Allison
@Allison
I have also implemented lightbox but my slices stay open when I click on images, but it’s far more simple script then your fancybox.
….thickbox, that’s the one I use, almost forgot to mention it:)
Nice exemples you’ve worked-out, yet I wonder whether it is possible to have the panels open “onhover” instead of “onclick”.
Thx in advance for your guidance.
I modified the jquery.vaccordion.js script to confine the navigation of the according to the title, arrows and scrolling of the mouse (i.e. nothing will happen when you click within a slice).
(function($) {
// Activate Slice Navigation
var slicenav = false;
// cache some values
var cache = {
idx_expanded : -1, // the index of the current expanded slice
sliceH : 0, // the default slice’s height
current : 0, // controls the current slider position
totalSlices : 0 // total number of slices
},
aux = {
// triggered when we click a slice. If the slice is expanded,
// we close it, otherwise we open it..
selectSlice : function( $el, $slices, $navNext, $navPrev, settings ) {
return $.Deferred(
function( dfd ) {
var expanded = $el.data(‘expanded’),
pos = $el.data(‘position’),
itemHeight, othersHeight,
$others = $slices.not( $el );
if (slicenav )
{
// if it’s opened..
if( expanded )
{
$el.data( ‘expanded’, false );
cache.idx_expanded = -1;
// the default values of each slices’s height
itemHeight = cache.sliceH;
othersHeight= cache.sliceH;
// hide the content div
$el.find(‘.va-content’).hide();
// control the navigation buttons visibility
if( aux.canSlideUp( $slices, settings ) )
$navPrev.fadeIn();
else
$navPrev.fadeOut();
if( aux.canSlideDown( $slices, settings ) )
$navNext.fadeIn();
else
$navNext.fadeOut();
}
//if it’s closed..
else
{
$el.data( ‘expanded’, true );
cache.idx_expanded = $el.index();
$others.data( ‘expanded’, false );
//the current slice’s height
itemHeight = settings.expandedHeight;
//the height the other slices will have
othersHeight= Math.ceil( ( settings.accordionH – settings.expandedHeight ) / ( settings.visibleSlices – 1 ) );
// control the navigation buttons visibility
if( cache.idx_expanded > 0 )
$navPrev.fadeIn();
else
$navPrev.fadeOut();
if( cache.idx_expanded < cache.totalSlices – 1 )
$navNext.fadeIn();
else
$navNext.fadeOut();
}
slicenav = false;
// the animation parameters for the clicked slice
var animParam = {
height : itemHeight + 'px',
opacity : 1,
top : ( pos – 1 ) * othersHeight + 'px'
};
// animate the clicked slice and also its title ()
$el.stop()
.animate( animParam, settings.animSpeed, settings.animEasing, function()
{
if( !expanded )
$el.find(‘.va-content’).fadeIn( settings.contentAnimSpeed );
})
.find(‘.va-title’)
.stop()
.animate(
{
lineHeight : cache.sliceH + ‘px’
}, settings.animSpeed, settings.animEasing );
// animate all the others
$others.each(function(i){
var $other = $(this),
posother= $other.data(‘position’),
t;
if( expanded )
t = ( posother – 1 ) * othersHeight ;
else {
if( posother = cache.totalSlices )
return false;
else if( dir === -1 && cache.current === 0 )
return false;
if( dir === -1 && cache.current === 1 )
$navPrev.fadeOut();
else
$navPrev.fadeIn();
if( dir === 1 && cache.current + settings.visibleSlices === cache.totalSlices – 1 )
$navNext.fadeOut();
else
$navNext.fadeIn();
}
else {
if( dir === 1 && cache.idx_expanded === cache.totalSlices – 1 )
return false;
else if( dir === -1 && cache.idx_expanded === 0 )
return false;
if( dir === -1 && cache.idx_expanded === 1 )
$navPrev.fadeOut();
else
$navPrev.fadeIn();
if( dir === 1 && cache.idx_expanded === cache.totalSlices – 2 )
$navNext.fadeOut();
else
$navNext.fadeIn();
}
var $currentSlice = $slices.eq( cache.idx_expanded ),
$nextSlice,
t;
( dir === 1 ) ? $nextSlice = $currentSlice.next() : $nextSlice = $currentSlice.prev();
// if we cannot slide up / down, then we just call the selectSlice for the previous / next slice
if( ( dir === 1 && !aux.canSlideDown( $slices, settings ) ) ||
( dir === -1 && !aux.canSlideUp( $slices, settings ) ) ) {
aux.selectSlice( $nextSlice, $slices, $navNext, $navPrev, settings );
return false;
}
// if we slide down, the top and position of each slice will decrease
if( dir === 1 ) {
cache.current++;
t = ‘-=’ + cache.sliceH;
pos_increment = -1;
}
else {
cache.current–;
t = ‘+=’ + cache.sliceH;
pos_increment = 1;
}
$slices.each(function(i) {
var $slice = $(this),
pos = $slice.data(‘position’);
// all closed or savePositions is false
if( !settings.savePositions || cache.idx_expanded === -1 )
$slice.stop().animate({top : t}, settings.animSpeed, settings.animEasing);
else {
var itemHeight, othersHeight;
// if the slice is the one we should open..
if( i === $nextSlice.index() ) {
$slice.data( ‘expanded’, true );
cache.idx_expanded = $slice.index();
itemHeight = settings.expandedHeight;
othersHeight = ( settings.accordionH – settings.expandedHeight ) / ( settings.visibleSlices – 1 );
$slice.stop()
.animate({
height : itemHeight + ‘px’,
opacity : 1,
top : ( dir === 1 ) ? ( pos – 2 ) * othersHeight + ‘px’ : pos * othersHeight + ‘px’
}, settings.animSpeed, settings.animEasing, function() {
$slice.find(‘.va-content’).fadeIn( settings.contentAnimSpeed );
})
.find(‘.va-title’)
.stop()
.animate({
lineHeight : cache.sliceH + ‘px’
}, settings.animSpeed, settings.animEasing );
}
// if the slice is the one opened, lets close it
else if( $slice.data(‘expanded’) ){
// collapse
$slice.data( ‘expanded’, false );
othersHeight = ( settings.accordionH – settings.expandedHeight ) / ( settings.visibleSlices – 1 );
$slice.stop()
.animate({
height : othersHeight + ‘px’,
opacity : settings.animOpacity,
top : ( dir === 1 ) ? ‘-=’ + othersHeight : ‘+=’ + settings.expandedHeight
}, settings.animSpeed, settings.animEasing )
.find(‘.va-title’)
.stop()
.animate({
lineHeight : othersHeight + ‘px’
}, settings.animSpeed, settings.animEasing )
.end()
.find(‘.va-content’)
.hide();
}
// all the others..
else {
$slice.data( ‘expanded’, false );
othersHeight = ( settings.accordionH – settings.expandedHeight ) / ( settings.visibleSlices – 1 );
$slice.stop()
.animate({
top : ( dir === 1 ) ? ‘-=’ + othersHeight : ‘+=’ + othersHeight
}, settings.animSpeed, settings.animEasing );
}
}
// change the slice’s position
$slice.data().position += pos_increment;
});
},
canSlideUp : function( $slices, settings ) {
var $first = $slices.eq( cache.current );
if( $first.index() !== 0 )
return true;
},
canSlideDown : function( $slices, settings ) {
var $last = $slices.eq( cache.current + settings.visibleSlices – 1 );
if( $last.index() !== cache.totalSlices – 1 )
return true;
}
},
methods = {
init : function( options ) {
if( this.length ) {
var settings = {
// the accordion’s width
accordionW : 825,
// the accordion’s height
accordionH : 400,
// number of visible slices
visibleSlices : 4,
// the height of a opened slice
// should not be more than accordionH
expandedHeight : 300,
// speed when opening / closing a slice
animSpeed : 250,
// easing when opening / closing a slice
animEasing : ‘jswing’,
// opacity value for the collapsed slices
animOpacity : 0.2,
// time to fade in the slice’s content
contentAnimSpeed: 900,
// if this is set to false, then before
// sliding we collapse any opened slice
savePositions : true
};
return this.each(function() {
// if options exist, lets merge them with our default settings
if ( options ) {
$.extend( settings, options );
}
var $el = $(this),
// the accordion’s slices
$slices = $el.find(‘div.va-slice’),
// the navigation buttons
$navNext = $el.find(‘span.va-nav-next’),
$navPrev = $el.find(‘span.va-nav-prev’),
$slicetitle = $el.find(‘h3.va-title’);
// each slice’s height
cache.sliceH = Math.ceil( settings.accordionH / settings.visibleSlices );
// total slices
cache.totalSlices = $slices.length;
// control some user config parameters
if( settings.expandedHeight > settings.accordionH )
settings.expandedHeight = settings.accordionH;
else if( settings.expandedHeight <= cache.sliceH )
settings.expandedHeight = cache.sliceH + 50; // give it a minimum
// set the accordion's width & height
$el.css({
width : settings.accordionW + 'px',
height : settings.accordionH + 'px'
});
// show / hide $navNext
if( settings.visibleSlices < cache.totalSlices )
$navNext.show();
// set the top & height for each slice.
// also save the position of each one.
// as we navigate, the first one in the accordion
// will have position 1 and the last settings.visibleSlices.
// finally set line-height of the title ()
$slices.each(function(i){
var $slice = $(this);
$slice.css({
top : i * cache.sliceH + ‘px’,
height : cache.sliceH + ‘px’
}).data( ‘position’, (i + 1) );
})
.children(‘.va-title’)
.css( ‘line-height’, cache.sliceH + ‘px’ );
// click event
$slicetitle.bind(‘click’, function() {
slicenav = true;
});
// click event
$slices.bind(‘click.vaccordion’, function(e) {
// only if we have more than 1 visible slice.
// otherwise we will just be able to slide.
if( settings.visibleSlices > 1 ) {
var $el = $(this);
aux.selectSlice( $el, $slices, $navNext, $navPrev, settings );
}
});
// navigation events
$navNext.bind(‘click.vaccordion’, function(e){
slicenav = true;
aux.navigate( 1, $slices, $navNext, $navPrev, settings );
});
$navPrev.bind(‘click.vaccordion’, function(e){
slicenav = true;
aux.navigate( -1, $slices, $navNext, $navPrev, settings );
});
// adds events to the mouse
$el.bind(‘mousewheel.vaccordion’, function(e, delta) {
slicenav = true;
if(delta > 0) {
aux.navigate( -1, $slices, $navNext, $navPrev, settings );
}
else {
aux.navigate( 1, $slices, $navNext, $navPrev, settings );
}
return false;
});
});
}
}
};
$.fn.vaccordion = function(method) {
if ( methods[method] ) {
return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === ‘object’ || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( ‘Method ‘ + method + ‘ does not exist on jQuery.vaccordion’ );
}
};
})(jQuery);
Why did you just paste that whole script in here? You could have at least linked to a js file on a server. If anyone copies and pastes this script into their code, they will pick up tons of formatted characters, mostly quotation marks but also minus symbols. Even after fixing those things, I still couldn’t get it to work.
@Erik van Dyck
In file jquery.vaccordion.js modify line #371 to following:
$slices.bind(‘mouseenter.vaccordion’, function(e) {
What about an autoplay?
Hi, i really liked this slide, but i need autoplay too, because i’m implementing in my website and him should be more dynamic. So anyone can help me?
I wanna start viewing slider not from thirst slide ((so i wanna hide thirs n slides). How can i do this? Ho can i scroll slider from my script!? I try somthing like
var a = setInterval(function(){
$(‘span.va-nav-prev’).click();
if (++m == elementNumber) clearInterval(a);
},400);
But it’s work VERY BAD!
Help me pleas! I can’t more(
This thing doesn’t work on iPad, doesn’t open when you press on it.
🙁
Just tested it on mine, works fine. iPad 2?
Any way to add a scrollbar to a slice when content is taller than the slice itself?
Please help!
What is the way to disable closing of the slice when i click on an element? I need to put some audio files (with JQuery media plugin). Right now it just closes the slice.
What is the best method?
Thanx in advance
To David Wathen!
Your version of jquery.vaccordion.js doesn’t work when i try to substitute the original. Could you explain in detail what you did to stop closing the slice when clicking on active elements???
did you ever figure this out?
Hi!
First off, this is beautiful. Love all your stuff.
I’m implementing this script (example 2) on my site and unfortunately it does not work properly in IE8 (all the other examples do work, except that one). It gets stuck after expanding one of the slices and one can’t navigate anymore at all.
Any ideas how to fix it?
Thanks a bunch!
Very Nice …
Why does it close when you click on the content of accordiion. It is not at all useful with the click on close. Please fix it
Can i have the slices be transparent so that the website’s background may be visible 🙁 HELP NEEDED!
Estimados los felicito, estoy adaptando el acordeon, pero quisiera que al hacer click en el contenido, este no se cierra. Segui el codigo que coloco David Wathen, pero revisando le falta codigo, con lo cual no resulto.
Ojala me respondan.
Saludos
Cristian
really Awsome tutuorial….but I have question man…is there any option to have one slide open by default….can u help me with this…what i mean is I have 4 slides when i enter or reload the page i want to be opened the 2nd slide by default, plz help me
Hi, great tutorial and really nice design… I was wandering if I can use your code to build my website, or is this just for demo purpose? tnx
I am also interested in the option to have a slider open as a default. I require the ‘Welcome’ section of a site to be open as a default initially, with the rest minimised. Is this possible?
Thanks for this accordeon! It works beautifully.
There is only one thing I cannot manage to do.
I have all my slices, wrapper and container with a transparent background, so I can to see my background image when the accordeon is closed.
Then I only the titles of each slice.
Tha works great.
I would like to put these titles very close to each other so , when you see the accordeon closed, you see a block of text with the lines superposed on the top and bottom borders. So then I see a block of letters.
The problem is that when I bring them close, even though ALL the backgrounds are transparent, they do not superspose but cut each other.
Is there any way I can do this?
Thanks!
To sat it more clearly……I want my ‘va.title’ classes to overlay on each other when my accordeon is closed and collapsed….
maybe this is more clear…
Is this possible?
Thanks!
Hi,
Is it possible to add a scrollbar on the right ?
If it’s possible, is there an easy way to do that ?
Thanks
For those trying to set it to open a slice on load, you can try
$(‘.va-slice-1’).trigger(‘click’);
that will display the contents of va-slice-1
also, I have mine so that instead of click, mine triggers on mouseenter (similar to hover), just change line 371 or the line that reads in the js file.
$slices.bind('click.vaccordion', function(e) {
with
$slices.bind('mouseenter.vaccordion', function(e) {