Skip to the content...

Welcome to the David Walsh Blog. I'm a MooTools, Dojo, jQuery, CSS, and PHP Web Developer located in Madison, Wisconsin, United States. Please contact me if I can make your experience on my website better.

Fancy FAQs with MooTools Sliders: Version 2

33 Responses »

A little over a year ago I authored a post titled Fancy FAQs with MooTools Sliders. My post detailed a method of taking boring FAQs and making them more robust using the world's best JavaScript framework: MooTools. I've taken some time to improve my original code for optimal performance and functionality.

The HTML

This is question 1

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae....

This is question 2

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae....

Our MooTools JavaScript will be reliant upon a simple HTML structure of H3s followed by DIVs.

The CSS

#faqs h3	{ cursor:pointer; }
#faqs h3.active	{ color:#d74646; }
#faqs div   {  }

You see I have very little CSS above -- just the bare necessities. It's up to you to make the content even more sexy. Maybe add some tweening on the content DIV when they show and hide.

The MooTools JavaScript

window.addEvent('domready',function() {
	$$('#faqs h3').each(function(header,i) {
		var state = false, answer = header.getNext('div');
		answer.slide('out');
		header.addEvent('click',function(e) {
			state = !state;
			answer.slide(state ? 'in' : 'out');
			if(state) {
				header.addClass('active');
			}
			else {
				header.removeClass('active');
			}
		});
	});
});

We start by grabbing all of the H3 tags within the designated parent element. We then:

  1. Cycle through each heading (the "question")
  2. Grab the next DIV and consider it our "content" container (the "answer")
  3. Slide the answer out of view
  4. Add a click event to the question which will toggle the display of the answer.

Another Take

The above code is accessible but sacrifices a clean effect during normal page load because you see a "flicker" of all of the answers displaying before JavaScript hides them. If accessibility is less of a concern and you want a smoother effect, consider adding the following CSS and JavaScript:

#faqs div	{ height:0; overflow:hidden; }

...and the JavaScript...

window.addEvent('domready',function() {
	$$('#faqs h3').each(function(header,i) {
		var state = false;
		var answer = header.getNext('div');
		answer.slide('out');
		header.addEvent('click',function(e) {
			state = !state;
			answer.slide(state ? 'in' : 'out');
			if(state) {
				header.addClass('active');
			}
			else {
				header.removeClass('active');
			}
		});
		answer.setStyles({
			overflow: '',
			height: 'auto'
		});
	});
});

This effect is much smoother.

So what do you think? Would you use this on a customer site?

Discussion

  1. October 21, 2009 @ 8:11 am

    great example, I was using the Accordion to get this effect, but your effect seems to make more sense + it’s much cleaner imo..

    So I will sure be using this, I also like the effect version as I was having the same trouble like the accessible demo.

    One question tho, is the slide something new ? or have I just missed this functionality from the documentation..

  2. October 21, 2009 @ 8:16 am

    Fx.Slide has been around for years! :)

  3. October 21, 2009 @ 8:27 am

    Just a quick idea – wouldnt it be better (for sake of user) to add cursor: pointer with javacsript? Because then if JS is turned off, users wont think it doesnt work (since clicking in h3 would do nothing)

  4. October 21, 2009 @ 8:43 am

    @David Walsh: hahah, yeah I read your previous version after I commented, just a short-hand for Fx.slide in this version.. didn’t know about that!

  5. alex
    October 21, 2009 @ 8:52 am

    Thanks very much for this David. I’m putting it into a client’s site today and am just experimenting with wrappers around the question/answer pair.

  6. andreas
    October 21, 2009 @ 8:58 am

    if(state) {
    header.addClass(‘active’);
    } else {
    header.removeClass(‘active’);
    }
    could be much shorter
    header[(state ?'add' :'remove') +'Class'](‘active’);

  7. October 21, 2009 @ 9:03 am

    @Adam Kiss: Yep, good idea.

    @Andress: I considered doing that but the code looks horrendous.

  8. October 21, 2009 @ 11:37 am

    To help with the “accessible” version, if you initially used answer.slide(‘hide’) instead of answer.slide(‘out’), the hiding would be instantaneous, instead of us watching the accordion collapse on load.

  9. October 21, 2009 @ 11:41 am

    @Sean McArthur: I considered that but you can still see a “flash” of the answers in the time before Moo is fully loaded and the domready event fires. I preferred the fold up effect to the “now it’s here…where the hell did they go?” feel.

  10. October 21, 2009 @ 12:41 pm

    Thanks for the tutorial. I created a sliding FAQ for a project about six months ago, and my solution wasn’t quite as elegant as this one.

  11. ed
    October 21, 2009 @ 1:53 pm

    Hi David,

    For a long list of questions I wouldn’t think this would be that optimal for usability.
    I’ve found this jQuery FAQ version which would work better for a longer list of questions.

    http://www.bitrepository.com/demo/fancy-faq/

    Is it possible to do something like that with MooTools as well?

    The main usability problem I see is that you when you start fold out questions things can get confusing, it takes more time to scan through to find a question you’ve glanced over and want to check back again for it.

    With the above linked version you can scan through questions and answers much faster.

  12. ed
    October 21, 2009 @ 2:08 pm

    Just found this blog post. :)

    http://davidwalsh.name/smooth-scroll-mootools

    Myself not being a coder, is it difficult to have the light up effect as well applied to a div David?

    Like in the previous lined example?

    Thanks!

  13. October 21, 2009 @ 6:14 pm

    ED – doesn’t do the highlight effect but I just put this together to simulate the jquery example you linked to:
    http://mooshell.net/a2ZMP/

  14. October 21, 2009 @ 7:08 pm

    @Ed: I’m not big on that verison — there’s far to much down, then up, down, then up with the window. Dizzying for me.

  15. October 21, 2009 @ 7:27 pm

    ….and of course exactly the same thing can be achieved with less code using FX.SmoothScroll as per your other demo that @Ed mentioned.

    Anyway, here is what I got to next: http://mooshell.net/gvY3V/
    Quite a lot less code (I posted my first attempt too soon) and does highlight the answer when it is scrolled to as requested by @Ed :)

  16. October 21, 2009 @ 7:46 pm

    David, just tested this faq code (your one) with mootools version 1.2.4 and it fails :(
    The faq answers are not being hidden, they just stack up on top of each other.

    This is not the first problem I have encountered with this latest version. As a mootools developer, do you have any idea *why* it doesn’t work?

  17. October 21, 2009 @ 7:48 pm


    answer.slide(state ? 'in' : 'out');
    if (state) {
    header.addClass('active');
    } else {
    header.removeClass('active');
    }

    how about

    answer.slide('toggle'');
    header.toggleClass('active');

    ;)

    And thx for using the .getNext() method, i didn’t know it it’s very useful sometimes!

  18. October 21, 2009 @ 7:55 pm

    As usual I should investigate things before writing…
    Just found an interesting comment with the reason/solution in the mootools blog about this new version:
    http://mootools.net/blog/2009/10/19/mootools-1-2-4/#more-412
    (see comment by Barryvan)

    Basically this latest release requires you to set the overflow:hidden as per your second demo.
    So this css gets it working in version 1.2.4:
    #faqs div { overflow: hidden;}

    That explains all the probelms I was having yesterday which eventually revert to version 1.2.3 :(

  19. ed
    October 22, 2009 @ 4:27 am

    @Chris Bolson:

    Thank you so much Chris! :)
    I couldn’t get the “To Top” function working at first, but then I noticed the “go_to_top” class was changed to “to_top” and it works great now!

  20. ed
    October 22, 2009 @ 4:28 am

    @David Walsh:

    You’re sitting to close to the screen then. ;)

  21. alex
    October 22, 2009 @ 5:28 am

    Any idea how to get this to work when the FAQ is initially hidden (by another mootools script). The height of the answers is initially ‘auto’ in this scenario (until the H3 is clicked twice).
    It’s not essential for my implementation, but it would be nice-to-have.

  22. evan
    October 22, 2009 @ 10:55 am

    I have a little trick that I used in the past to solve the flicker problem and still keep the page accessible for users who don’t have JS.

    The flicker is because we wait for domready to fire before you can start to collapse the copy.

    What I do is place a class on my body tag .

    Then I place some script right after the body tag that immediately removes the no-script class from the body. Obviously if the user does not have JS the class will remain on the page.

    You can now style your page differently for users who don’t have JS.
    #faqs div { height:0; }
    .no-script #faqs div { height:auto; }

    Because you are removing the class before a load or domready event you can get the flicker to pretty much go away.

  23. October 23, 2009 @ 6:48 am

    I’ll us it on the mobile Mooshell version :D

  24. October 24, 2009 @ 5:07 am

    Here’s a jQuery version for those of us that prefer that framework :

    $(function() {
    // 1. hide the faqs
    $(‘#faqs h3′).next().hide();

    // 2. show when clicked
    $(‘#faqs h3′).click(function() {
    $(this).toggleClass(‘active’).next().slideToggle();
    });
    });

  25. November 3, 2009 @ 8:03 pm

    Exactly what I was looking for. Excellent!

  26. November 18, 2009 @ 7:09 am

    I’ve rewritten a couple of lines to make the first div active, visible. This is what I came up with:

    var i = 0;
    $$(‘#faqs h3′).each(function(header,i) {
    var state = false, answer = header.getNext(‘div’);

    if(i > 0){
    answer.slide(‘out’);
    }else{
    state = !state;
    header.addClass(‘active’);
    }

    header.addEvent(‘click’,function(e) {
    state = !state;
    answer.slide(state ? ‘in’ : ‘out’);
    if(state) {
    header.addClass(‘active’);
    }
    else {
    header.removeClass(‘active’);
    }
    });

    answer.setStyles({
    overflow: ”,
    height: ‘auto’
    });

    i++;
    });

    I’ll hope that this is usefull for other readers!

  27. November 18, 2009 @ 8:30 am

    @Crispijn: Why not keep my “core” code the same but simply fireEvent(‘click’) on the first item?

  28. November 18, 2009 @ 8:31 am

    @David Walsh: Haven’t thought about that! That’s even better! Thanks

  29. December 30, 2009 @ 7:50 pm

    @Dave Jones:

    I upload it code, but it not work.
    Some idea?

    $(function() {
    // 1. hide the faqs
    $(‘#faqs h3′).next().hide();

    // 2. show when clicked
    $(‘#faqs h3′).click(function() {
    $(this).toggleClass(‘active’).next().slideToggle();
    });
    });

    #faqs h3 { cursor:pointer; }
    #faqs h3.active { color:#d74646; }
    #faqs div { height:0; overflow:hidden; }

    This is question 1

    Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae….

    This is question 2

    Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae….

  30. December 30, 2009 @ 7:53 pm

    [!DOCTYPE HTML...
    [html...
    [head
    [script src=http://code.jquery.com/jquery-latest.js...

    $(function() {
    // 1. hide the faqs
    $(‘#faqs h3′).next().hide();

    // 2. show when clicked
    $(‘#faqs h3′).click(function() {
    $(this).toggleClass(‘active’).next().slideToggle();
    });
    });

    [/script]
    [style type="text/css"]
    #faqs h3 { cursor:pointer; }
    #faqs h3.active { color:#d74646; }
    #faqs div { height:0; overflow:hidden; }
    [/style]
    [/head]
    [body]
    [div id="faqs"]
    This is question 1

    Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae….

    This is question 2

    Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae….

  31. matt
    January 25, 2010 @ 4:56 pm

    Hey guys,

    it’s been some time since i’ve been here but I wanted to know if I had a link within an email can I have this link to the page with the question already open?

  32. March 3, 2010 @ 5:10 am

    Hi David – or anybody here to help me?

    Is it possible:
    1. Turn the animation off?
    2. Click anywhere to close the open part(s)?

    I´m sitting here and can´t get it right…

    Thanks for help!!

    Martin

  33. eliot slevin
    July 30, 2010 @ 2:54 pm

    i have no experience in js, but is it possible to have one question close when another is opened?

    thanks

Be Heard!

Share your thoughts with fellow developers of all skill levels! I want to hear from you!

Name*:
Email*:
Website:  
Wrap your code with <code> tags, f00!