Fancy FAQs with MooTools Sliders: Version 2

By  on  

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, answer = header.getNext('div');
		answer.slide('out');
		header.addEvent('click',function(e) {
			state = !state;
			answer.slide(state ? 'in' : 'out');
			header[(state ? 'add' : 'remove') + 'Class']('active');
		});
		answer.setStyles({
			overflow: '',
			height: 'auto'
		});
	});
});

This effect is much smoother.

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

Recent Features

  • By
    CSS vs. JS Animation: Which is Faster?

    How is it possible that JavaScript-based animation has secretly always been as fast — or faster — than CSS transitions? And, how is it possible that Adobe and Google consistently release media-rich mobile sites that rival the performance of native apps? This article serves as a point-by-point...

  • By
    An Interview with Eric Meyer

    Your early CSS books were instrumental in pushing my love for front end technologies. What was it about CSS that you fell in love with and drove you to write about it? At first blush, it was the simplicity of it as compared to the table-and-spacer...

Incredible Demos

  • By
    Using MooTools to Instruct Google Analytics to Track Outbound Links

    Google Analytics provides a wealth of information about who's coming to your website. One of the most important statistics the service provides is the referrer statistic -- you've gotta know who's sending people to your website, right? What about where you send others though?

  • By
    PHP IMDB Scraper

    It's been quite a while since I've written a PHP grabber and the itch finally got to me. This time the victim is the International Movie Database, otherwise known as IMDB. IMDB has info on every movie ever made (or so it seems). Their...

Discussion

  1. 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. Fx.Slide has been around for years! :)

  3. 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. @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

    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
    if(state) {
    	header.addClass('active');
    } else {
    	header.removeClass('active');
    }
    

    could be much shorter

    header[(state ?'add' :'remove') +'Class']('active');
    
  7. @Adam Kiss: Yep, good idea.

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

  8. 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. @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. 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

    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

    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. 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. @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. ….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. 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. 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. 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

    @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

    @David Walsh:

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

  21. Alex

    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

    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. I’ll us it on the mobile Mooshell version :D

  24. 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. Exactly what I was looking for. Excellent!

  26. 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 useful for other readers!

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

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

  29. Matt

    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?

  30. 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

  31. Eliot Slevin

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

    thanks

  32. Vilius

    Is there a simple way to let only one item active ?

    • Tony Z

      Great stuff. A couple of things I would be interested in.
      1. Code to show all or hide all answers.
      2. Ability to restrict to only show 1 answer at a time (auto close when another question is selected).

      Any

  33. good idea and good work. thanks…

  34. Using this on my site with the following CSS for a nice show hide text change:

    #faqs h3:after	{ content: " - show"; }
    #faqs h3.active:after	{ content: " - hide"; }
    

    Nice one on this simple but powerful little script David! Thanks

    • rolandtom

      Dan, great addition!

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!