I was using Mootools Fx.Slide to create a list based FAQ section, and ran into a bit of a problem while making all of the list items collapse or expand. The solution is quite simple, but not immediately obvious. In this article I’ll demonstrate how to expand and collapse all of the items in a list, and also a way to simulate an accordion. Before we go any further, check out a demo page for this article.

Applying slide effect to a single element is straight forward and looks something like this:

var collapsible = new Fx.Slide($('target-element'), {
	duration: 500,
	transition: Fx.Transitions.linear
});

collapsible.toggle();

What’s not immediately obvious is that, the code above takes the target element and wraps it into a div with overflow set to hidden. Whenever Fx.Slide is toggled, negative margin is applied to the target element and it, sort of, slides under the wrapping div. Take a look at the HTML before and after the effect was applied:

<!-- before the effect is applied -->
<li>
	<div  class="collapse">
		<p>Some text here</p>
	</div>
</li>

<!-- after slideIn effect was applied -->
<li>
	<div style="overflow: hidden; height: 0px;">
		<div class="collapse" style="margin: -100px 0 0;">
			<p>Some text here</p>
		</div>
	</div>
</li>

<!-- after slideOut effect was applied -->
<li>
	<div style="overflow: hidden; height: 100px;">
		<div class="collapse" style="margin: 0;">
			<p>Some text here</p>
		</div>
	</div>
</li>

Once you understand how Fx.Slide functions, it becomes clear that this effect cannot be applied to any particular target more than once. With that in mind, the solution for collapsing or expanding all items is quite simple – store all of the Fx.Slide references in an array, then upon a request loop through the array and for each element in it, apply the desired effect. Here is the code:

//list of target elements
var list = $$('#collapse li div.collapse');
//list elements to be clicked on
var headings = $$('#collapse li h3');
//array to store all of the collapsibles
var collapsibles = new Array();

headings.each( function(heading, i) {

	//for each element create a slide effect
	var collapsible = new Fx.Slide(list[i], {
		duration: 500,
		transition: Fx.Transitions.linear
	});

	//and store it in the array
	collapsibles[i] = collapsible;

	//add event listener
	heading.onclick = function(){
		collapsible.toggle();
		return false;
	}

	//collapse all of the list items
	collapsible.hide();

});

//collapse all
$('collapse-all').onclick = function(){
	headings.each( function(heading, i) {
		collapsibles[i].hide();
	});
}

//expand all
$('expand-all').onclick = function(){
	headings.each( function(heading, i) {
		collapsibles[i].show();
	});
}

Also, by adding just a few more lines of code we can simulate an accordion:

headings.each( function(heading, i) {

	//for each element create a slide effect
	var collapsible = new Fx.Slide(list[i], {
		duration: 500,
		transition: Fx.Transitions.linear
	});

	//and store it in the array
	collapsibles[i] = collapsible;

	//add event listener
	heading.onclick = function(){

		//open current element
		collapsible.toggle();

		//hide the rest
		for(var j = 0; j < collapsibles.length; j++){
			if(j!=i) collapsibles[j].slideOut();
		}

		return false;
	}

	//collapse all of the list items
	collapsible.hide();

});

Take a look at the source code of the demo page to see more elaborate code examples.


55 Responses to “Mootools Slide Effect: expand all, collapse all or use as accordion”

  • hey this is nice work…how would you go about modifying it so that the accordions are open/closed by a mouse hover?

  • It’s quite simple, really - just use onMouseOver instead of onClick:

    heading.onmouseover = function(){
    

    Or you can use onMouseEnter:

    heading.addEvent('mouseenter', function(e){
    	var span = $E('span', heading);
    
    	if(span){
    		var newHTML = span.innerHTML == '+' ? '-' : '+';
    		span.setHTML(newHTML);
    	}
    
    	for(var j = 0; j < collapsibles.length; j++){
    		if(j != i) {
    			collapsibles[j].slideOut();
    			if(spans[j]) spans[j].setHTML('+');
    		}
    	}
    
    	collapsible.toggle();
    
    	return false;
    
    });
    
  • Really cool stuff! For the accordion, they are all closed initially. How would you set it to expand the first “item” when the page loads?

  • You could just place this code “collapsibles[0].toggle();” at the very end of the accordion function - that would collapse all items and then open up the first one.

    More efficient way, however, would be to replace “collapsible.hide();” with “if(i != 0) collapsible.hide();” - that would leave the first element open.

  • […] thing to note is a customized Accordion effect .  I was looking for a way to use mootools to review an answer when the user click on a […]

  • Hi,
    thank’s for your quick and very clear tutorial (and the more elaborate demo). Exactly what I needed for a better understanding on how deal in mootools with multiple items and to apply effects on them.

  • Hi Sml,

    while I can’t really tell “exactly” what you need for better understanding of Mootools, I can recommend using Firebug plugin for Firefox - it is an absolute must-have for a web developer.

  • hoi, this is a very nice work. :) how I can modify the vertically slide effect, so that only are defined boxes open. so, the default values overwrite via window.addEvent('domready',...) the js-file. the js-file should remain unchanged. thank.

  • Green, I believe this particular question has already been discussed on Mootools forums - just take a look around there.

  • Great demo. Is it possible to have the “accordion” inside the “slide-effect”?

  • Aram, that should be fairly easy to accomplish. Just add another level to the list and attach accordion behavior to it - simple :)

  • Great Work …..
    when i tried with onMouseOver its slides in nicely but i need to mouseover again to slide out…. Is there any solution for this…..
    It should be like when ever the mouse is over the heading it slides the content. and when ever the mouse is out of heading or content It should slide out….

  • Pravin, you should use onMouseOut instead.

  • hi, nice work! how did you manage to add the round corners to the gif’s and how can i manage to get rid of this function? i couldn’t find the relating parts in the script. thank’s a lot, cheers, jan

  • Hi Jan, the rounded corners have nothing to do with the script itself. They are applied via CSS. Use your own style sheets to make the slides look however you wish :)

  • hi Alex,

    i know, i was just curious how they were created, couldn´t figure it out so far…what’s the css method called to create them, so i can google it. i still got no clue looking at your stylesheet :-). cheers from freiburg/germany, jan

  • Jan, CSS (Cascading Style Sheets) is beyond the scope of this article. Basically, it is the glue between HTML and graphics. I strongly recommend that you learn HTML/CSS basics, before jumping into JavaScript.

  • Hey, awesome script…

    but how would i go about creating a collapse container in a container….
    so in the demo .. i wish to have another accordion inside an accordion (item 1, then another button to collapse inside it) … thanks.

  • Daniel, first of all, I wouldn’t recommend using such structure - it will make finding a particular slide rather hard. If you still wish to use nested accordions, it should be fairly simple to make. If you need help on this matter, please go to MooTools forums.

  • Awesome script, this saved my butt when I couldn’t get other accordion scripts to work in IE6.

    Is there a way to toggle a specific collapsable after the script has been loaded? I’m trying to create a link to toggle a certain collapsed layer, but can’t figure out how to do it.

    Thanks again!

  • Jeremy, sorry for the late reply. Yes, it’s possible - the solution is quite simple, in fact. Just add attribute rel=”dontcollapse” to the divs you wish to keep open and take a look at the code below:

    headings.each( function(heading, i) {
    
            //for each element create a slide effect
            var collapsible = new Fx.Slide(list[i], {
                    duration: 500,
                    transition: Fx.Transitions.linear
            });
    
            //and store it in the array
            collapsibles[i] = collapsible;
    
            //add event listener
            heading.onclick = function(){
                    collapsible.toggle();
                    return false;
            }
    
            //collapse all of the list items except for elements with rel="dontcollapse"
            var dontCollapse = collapsible.getProperty('rel');
            if(dontCollapse != 'dontcollapse') collapsible.hide();
    
    });
    

    I haven’t had any time to test the code, but in any case you should be able to get it running :) Also, you may want to check out MooTools forums, there is a solution (for this particular script) that uses cookies to remember slides’ positions.

  • hey great script, quick question…

    Is there anyway to make a “slide all” button, where instead of hiding/showing all of them, a single button slides/unslides them all

    thank you

  • Use toggle method instead… You can find out more in MooTools official docs.

  • thanks alex, im working on it right now

    what im trying to do is have multiple sliding menus on a single page, in different areas and sliding in different directions all countrolled by a single button

    do you think this would be possible with toggle?

  • I’m not really sure of what you are trying to accomplish. There are only 5 methods: hide, show, toggle, slideIn, slideOut - I think their intention is obvious. With the right combination of those you can achieve the effect you’re after. Once again, if you need some more info on those methods - check the official docs.

  • Is there a way to have it not flash the content of the collapse div when loading?

  • You may just have a lot of content or a slow PC - I haven’t really came across this issue. What you are after, however, is quite simple to accomplish, but it will create accessibility issues.

    At the moment all of the slides are open by default and collapsed once DOM is loaded, with the use of JS; if a user’s web browser does not support JS, then there will not be a slide/collapse effect, but all of the content will still be readable/visible.

    You can hide all of the content with the use of CSS. Doing so will rid of the content flash completely, but if a user’s browser does not support JS, they won’t be able to see anything inside the slides.

    Hope that made sense :)

  • I don’t have that slow of a PC. It’s a newer Intel Mac with 2GB of ram. I am loading content from a database, would that make a difference? I’m also having a heck of a time getting the slide boxes to show all of the content. Any CSS tips on that? It doesn’t seem to have a rhyme or reason. The test server is at http://141.209.36.46/somsite/events/concerts/
    I’ve tried setting the height to auto and 100%, but the only thing that seems to work is setting a defined height, which I don’t really want to do.

  • I see that you’re using slides as an accordion - that is not the best way to go. I’ve only included it in the demo as a proof of concept, I guess. The accordion plug-in, packed with MooTools, will work much better in your case.

    As for the hidden content - just add a bit of extra padding at the bottom should do the trick.

  • hey alex, thanks for your quick responses, i found what i was after…

    can you post a link or a quick code for a cookie that remembers the position of the menu? (i tried looking on the forum but i wasnt able to implement the code to this script)

  • What is it that will work much better? I can’t seem to get the built-in accordion to do what I want. For some reason I can’t figure out how to have it load with all collapsed, and have the + turn to -. Mainly because I have no javascript skills. I am learning though. Thanks for the help you’ve been.

  • @tomms - I don’t have the links, sorry. It should be there, I’ve seen quite a few referrers from it as one point in time.

    @Jon - The Accordion plug-in just seems much faster and responsive. It doesn’t allow for all of the slides to be closed, I believe.

  • Thanks Alex, you’ve been more than enough help for me. I’ve got it working using the standard accordion now. Now all I have left is to figure out that little + - change you got going on there…

  • Gravatar
    March 26th, 2008 at 7:23 pm
    Mara Alexander says:

    Thank you Alex!!! You explained the fx.slide in a way I wasn’t getting from either the docs or the mootools forum. It makes SENSE now:)

  • What can be added to the javascript to force the first element in the accordion list to be open when you first go to the pagee?

  • I noticed the collapse element does indeed ‘flash’ or flicker its visibility while collapsing (sliding). Tested on multiple browsers/computers. Ive noticed a similar type of behavior in mootools when visibility is set to 0, but I’m not sure that’s what causing this. I need to dig around the Slide class to see whats going on w visibility. But this flickering is an issue here.

    You said “using slides as an accordion - that is not the best way to go. I’ve only included it in the demo as a proof of concept, I guess. The accordion plug-in, packed with MooTools, will work much better in your case.”

    Well, accordion would be perfect if it collapsed all elements which it doesn’t. Bummer if your Slide accordion isn’t the solution b/c of the flicker. …

    Thanks for the work.

  • You can see it flicker better with taller elements. here:
    http://ziiglab.org/test/accordoslide.php

  • I only have a bit of flickering in Firefox 2.* under Windows XP. Other browsers run rather smoothly, including Firefox 2.* under Linux. Not really sure where the problem lies - whether it’s Firefox’s engine or perhaps inefficient use of code. I’ll look into this though, in the near future. Perhaps MooTools 1.2 will resolve this, if not I may come up with a custom slide plugin - we’ll see :)

  • OK Alex, I see you are just demoing some slide stuff here which is cool.

    Here is the solution for collapse all accordion if anyone is interested:
    First use the extended accordion here-
    http://forum.mootools.net/viewtopic.php?id=2713

    And for options on initialize, the documentation in mootools explains two options: alwaysHide and display. Initialize in the following way (note to change to your togglers and panels):

    myAccordion = new ExtendedAccordion('togglers', 'panels', {display:-1, alwaysHide:true});

    And that will do it with accordion.

    Thanks for the slide example, would be interesting to see whats making it flicker. Ive seen mootools have other strange flickering bugs in other fx.

  • Tyler, it’s not just a demo - the purpose of this article is to show how to manipulate multiple slides at once. The solution for this is not immediately obvious, as MooTools modifies the original DOM structure. Accordion is just a byproduct here.

    Thanks for your input though, perhaps it will help someone :)

  • Hi Alex,

    Great code. Here is rather simple solution to include the use of cookies to remember the state of the panel. It sets a cookie when the panel is clicked and removes again it when closed. It will show / hide the panel (without transition) when the page is loaded based on whether or not the cookie exists.

    It probably can be refactored better but I hope it is of some use to someone!


    collapsibles[i] = collapsible;
    if (Cookie.get("menu_"+i)) {
    collapsible.show();
    }
    else {
    collapsible.hide();
    }

    heading.onclick = function(){
    var span = $E('span', heading);
    if(span){
    var newHTML = span.innerHTML == '+' ? '-' : '+';
    span.setHTML(newHTML);
    }

    if (Cookie.get("menu_"+i)) {
    Cookie.remove("menu_"+i);
    }
    else {
    Cookie.set("menu_"+i, true);
    }

    collapsible.toggle();
    return false;
    }

    //collapsible.hide();

  • Thank u very much for the cookie-code!

  • Hy! Your works is great!!
    I’ve the question: i want open one or more div at the start page. I’ve past the code you write in recent comment but don’t work.
    You can help me, please?!!

    Sorry for my english but don’t speak very well!! :(

  • Sorry… I forgot one question: how can I make the previous div automatically close when I click on the next one?

    Thanks!

  • Gravatar
    May 8th, 2008 at 6:50 am
    Andrew Williams says:

    Hi, i have run into a few problems with this script. My first problem is that the collapser tags are cutting my table off by about 300 pxs. Secondly the collapse tags don’t like large styled divs in them. Is there a width/length limit for these collapse tags?

  • Andrew, there are no limits, the script adjusts to dimensions automatically. My guess is that something is wrong with your CSS.

  • Gravatar
    May 8th, 2008 at 10:44 am
    Andrew W says:

    Ah i found the problem. One of my inner content areas had content floating left which for some reason makes it disappear (Fixed by putting content into nested tables.) and the other was due to a length in my css file. Thanks Alex.

  • Hi

    Great code!
    Is it possible to have the url of the list based FAQ section to see your work please.
    Thks

  • I see you use the traditional onclick assignment for registering click event handlers. Any particular reason why you don’t use MooTools addEvent()?

    Incidentally, I wrote an article comparing MooTools’ mouseenter and mouseleave events to core JavaScript onmouseover and onmouseout, respectively:

    http://www.thetruetribe.com/2008/05/mootools-mouseenter-and-mouseleave.html

  • Hi,

    I see how you have the + / - change when you click the heading.

    Is there a way to use a background image on a span or even an image tag via and have an image change when you click the heading?

    Thanks

  • Wow what a great example! Thank you for putting it together for us. And that’s very useful cookie code Andrew, thanks!

    I have a question: I know you can toggle a single div to show all or none of the content. But is it possible to have part of the div showing at all times, say the top 40%, and the rest hidden until toggled? I know the bottom part can be a separate div but for me it has to be only one div. Is that possible do you think?

  • Hi,

    Great work, exactly what i was looking for! I’ve been building an entire site based around Mootools to provide an interactive user experience and your code helped me finish off the bits i couldn’t work out.

    Regards Harry

  • This comment thread scares me. I feel like a lawyer or doctor where there are twice as many no-nothings fronting as developers as there are actual developers. Please stop abusing MooTools, it is a great framework, but all of you knuckleheads are going to give it a bad name. Accordions inside of accordions? Come on, stop being ridiculous and learn how to code a basic static page before you go copy/pasting effects all over your sites. Alex, you’re a man among boys.

  • Hi,
    Nice code but I have been looking to replace + and - and you can do this fine with text but in terms of the accordion when you want to say use - View ^ with ^ being a down image for view and Close ^ being up to close if you set two variables for view and close and in them have say ‘close ‘ while replacing close will show the image and function correctly if you try and add an image in terms of the view the code works but the close view switching breaks.

    Any ideas? I was thinking going old school a little and instead of doing innerHTML you could do document.write and replace instead which would solve the problem but that means a full re-write in terms of the span.

    One good feature to add to this though is display:block; to the h3 or if you change it to a div etc that way the whole bar basically would be a link and it feels a bit more user friendly.

  • That’s it, seems that there is nothing further to contribute here - I’m closing the comments.