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 jQuery Sliders

51 Responses »
jQuery

Frequently asked questions can be super boring, right? They don't have to be! I've already shown you how to create fancy FAQs with MooTools -- here's how to create the same effect using jQuery.

The HTML

<h3>This is question 1?</h3>
<div>
	<p>This is the answer to question #1.  Pellentesque habitant morbi....</p>
</div>
<h3>This is question 2?</h3>
<div>
	<p>This is the answer to question #2.  Pellentesque habitant morbi....</p>
</div>
<!-- more... -->

Simply a series of H3s and DIVs wrapper in one container DIV. Simple, simple, simple.

The CSS

#faqs { position:relative; }
#faqs h3	{ cursor:pointer; }
#faqs h3.active	{ color:#d74646; }
#faqs div   { position:relative; }
#faqs div p	{ padding:0; margin-bottom:15px; }

Nothing out of the ordinary above -- format the elements as though there wont be a jQuery component.

The jQuery JavaScript

$(document).ready(function() {
	$('#faqs h3').each(function() {
		var tis = $(this), state = false, answer = tis.next('div').slideUp();
		tis.click(function() {
			state = !state;
			answer.slideToggle(state);
			tis.toggleClass('active',state);
		});
	});
});

Start by collecting and recursing through all of the H3 elements. Grab the DIV that follows, slide it in, and add click handlers to slide them in and out!

A More Elegant Effect

The above method is the more accessible version. If effects are you priority, the following CSS and jQuery JavaScript variants will make for a more elegant effect by preventing the initial slide in:

#faqs h3	{ cursor:pointer; }
#faqs h3.active	{ color:#d74646; }
#faqs div { height:0; overflow:hidden; position:relative; }
#faqs div p	{ padding:0; margin-bottom:15px; }
$(document).ready(function() {
	$('#faqs h3').each(function() {
		var tis = $(this), state = false, answer = tis.next('div').hide().css('height','auto').slideUp();
		tis.click(function() {
			state = !state;
			answer.slideToggle(state);
			tis.toggleClass('active',state);
		});
	});
});

There you have it. Have fun with your FAQs!

Discussion

  1. February 10, 2010 @ 9:29 am

    It jumps a little at the end of the transition when you expand the answer div, can you use easing or similar to improve this?

  2. February 10, 2010 @ 9:47 am

    I did notice that Alex. It seems to me it’s a jQuery thing, as MooTools doesn’t jump. It’s to do with the P tag having margin or padding — anyone know the preferred jQuery hack for this?

  3. February 10, 2010 @ 9:53 am

    I’m sure I had a similar issue with jumping on a clients site once, I fixed it with fixed height container ( in this example) but with variable length faq answers its not ideal.

  4. February 10, 2010 @ 9:58 am

    I’d put it in a DL if I was you, but nice simple tutorial, and I’d make only one visibile at the time maybe ?

  5. February 10, 2010 @ 10:00 am

    Use padding instead of margin on the P’s and see if that works (that’s what your Moo version does). Although the preferred hack is to only use .slideToggle stuff on element which don’t have margin or padding (and put the padding on things inside of that.

    Also, all the jQuery people out there always go OMG??!! you used the $(this) selector more than ONCE in a function, you should cache that with $el = $(this) and then use the cached version. So:

    OMG??!! you used the $(this) selector more than ONCE in a function, you should cache that with $el = $(this) and then use the cached version.

  6. February 10, 2010 @ 10:12 am

    @Chris Coyier: The problem was happening with P’s as well.

  7. February 10, 2010 @ 10:18 am

    @All: Updated to prevent @Chris Coyier’s OMG-ness.

  8. guido
    February 10, 2010 @ 10:53 am

    It’s not really smooth, i like spry accordion tabs more.

  9. February 10, 2010 @ 11:48 am

    well done,but only one things: “$(this)['slide' + (state ? 'remove' : 'add') + 'Class'](‘active’); ” gave me an error.

  10. February 10, 2010 @ 11:53 am

    @xeon: Make sure it isn’t the stupid WordPress quotes around the word “active” — make sure they’re regular single quotes.

  11. February 10, 2010 @ 11:59 am

    @David Walsh: It’s all because of height. If you set the height of each P tag, that won’t happen. Something like $(‘p’).each(function(){ $(this).height($(this).height()) }); should fix.

    @Mohamed Jama: Me too. It’s more semantic.

  12. February 10, 2010 @ 11:59 am

    @David Walsh: this is the error:
    $(this)["slide" + (state ? "remove" : "add") + "Class"] is not a function

    @http://davidwalsh.name/dw-content/fancy-faqs-jquery.php?version=effect (line 122)

  13. February 10, 2010 @ 12:22 pm

    @xeon: Use the updated code above — picture perfect.

  14. February 10, 2010 @ 12:50 pm

    Nice post…

    I would have used / elements though – the html would have been more semantically correct…

  15. February 10, 2010 @ 12:52 pm

    lol, oops – let’s clarify that :) dd and dt elements would have been more semantically correct…

    Putting a whole bunch of /’s in might be therapeutic to some, but kinda pointless to most :)

  16. rob simpkins
    February 10, 2010 @ 1:14 pm

    Nice effect, and the height bug is annoying; however isn’t this reinventing the wheel somewhat… jQueryui has the accordion plugin already.

    Just a thought.

  17. February 10, 2010 @ 2:37 pm

    Hey David. A couple simple things I would change.

    First, the jumping bug: Add `position:relative` to your `#faqs` div, and it will start working as you expect.

    Second, use `slideToggle` and `toggleClass` instead of the (clever) ternary operator stuff. Most of the `toggle` type functions in jQuery take an optional boolean to specify which to run.

    state = !state;
    answer.slideToggle( state );
    tis.toggleClass( ‘active’, state );

  18. mike mcbrien
    February 10, 2010 @ 2:55 pm

    In google chrome dev edition.. version 5.0.317.2 the HTML code does not show in your example html/code blocks.

  19. February 10, 2010 @ 6:49 pm

    Also, make sure you apply display:"none" to the inner divs. That will get rid of the jump while the page is loading, then set it back to display:"block" with jQuery after you set the height to zero.

    Example:

    $(".answer").css({ height:0, display: "block"});

    You can also wrap the inner html in the answer div with another div and give the new div the padding.

    Check this screencast out: http://jqueryfordesigners.com/slidedown-animation-jump-revisited/ It solves all your problems.

    Regardless, you have a great blog man! It is basically carved in my RSS reader.

    Cheers,

  20. alex
    February 10, 2010 @ 9:43 pm

    hmmmm I prefer the mootools effect

  21. daniele
    February 11, 2010 @ 1:55 am

    Hi, maybe you can fix the problem with div height this way (sometimes it works)

    $(‘#faq div’).each(function() {$(this).height($(this).height()); });

  22. daniele
    February 11, 2010 @ 1:57 am

    Hi, maybe you can fix the problem with div height this way (sometimes it works)

    $(‘#faq div’).each(function() {$(this).hide().height($(this).height()); });

  23. February 11, 2010 @ 6:21 am

    Why even have a MooTools version? Surely jQuery is so much better for everything?! /troll

  24. February 11, 2010 @ 3:52 pm

    That margin jump in jQuery is particularly annoying here. Firefox 3.6.

    It even happens on the jQuery homepage demo D:

  25. February 11, 2010 @ 5:25 pm

    @Darkimmortal It does indeed! I contacted Ralph Whitbek about it, and he opened this ticket: http://dev.jquery.com/ticket/6078 It should be fixed at some point soon.

  26. February 11, 2010 @ 10:02 pm

    @Douglas Neiner: It’s all fixed.

  27. February 12, 2010 @ 1:26 am

    @Ralph Whitbeck: nope, it’s still here :)

  28. February 12, 2010 @ 1:33 am

    @Zy @Ralph Whitbek Its fixed for me in Safari 4 and Firefox 3.5 (whereas it was broken before with the jump) Caching maybe?

  29. February 12, 2010 @ 10:50 am

    @Zy It’s fixed on the jQuery homepage, but still broken on this demo.

  30. February 12, 2010 @ 7:27 pm

    This is very a good tutorial. Thanks for posting! By the way there is a problem with the height as some people posted before, but other than that its pretty good.

  31. February 13, 2010 @ 5:25 am

    Nice! jQuery is a great framework, it’s cross browser compatible and lends itself to progressive enhancement very well!

  32. February 13, 2010 @ 10:01 am

    Nicely done. I didn’t experience any issue with the height.

  33. February 13, 2010 @ 5:39 pm

    The fix for jQuery’s animation jump can be found on jQuery for designers: http://jqueryfordesigners.com/slidedown-animation-jump-revisited

    It worked for me on a previous project.

  34. February 13, 2010 @ 11:45 pm

    Great stuff – I’m building my site as we speak and this will definitely be included in it – I was just checking your pages and BooM dunk. Anyhow, I have a question for ya. When I was selecting tutorial to copy it and read it later (off-line) I noticed that on copied text or whatever you select – your cute LOGO shows up – that probably takes you somewhere to “explain selected field” if I understand correctly coz I couldn’t open that page (maybe it’s a bug problem). I was thinkin CAN YOU PLEASE GAVE US TUTORIAL ON THAT TRICK???? Please

  35. February 13, 2010 @ 11:47 pm

    Great stuff – I’m building my site as we speak and this will definitely be included in it – I was just checking your pages and BooM dunk. Anyhow, I have a question for ya. When I was selecting tutorial to copy it and read it later (off-line) I noticed that on copied text or whatever you select – your cute LOGO shows up – that probably takes you somewhere to “explain selected field” if I understand correctly coz I couldn’t open that page (maybe it’s a bug problem).

    I was thinking – CAN YOU PLEASE GAVE US TUTORIAL ON THAT TRICK???? Please and thanks a lot for great stuff as always!

  36. geler
    February 14, 2010 @ 9:55 am

    @David Walsh: this happen when you slide on a tag with padding or margin. to avoid this you must add a tag. put your p insde a div, slide the div and margin/padding on the p

  37. February 14, 2010 @ 1:21 pm

    O ;) nice – lol – sorry. Can you repeat that but in plain English so i could understand something. Please understand. Thanks@Geler:

  38. February 16, 2010 @ 12:43 pm

    Here is my stab at FAQs.

    I used definition list for markup

    http://ranjandatta.com/jquery/dlToggle/

  39. February 19, 2010 @ 1:14 pm

    Hey, David,

    Any objection to me using the jQuery to showcase another way to use it? I’ll of course give you credit for it. All I did was play with the CSS to see how it could be used as another tool and came up with something potentially handy. Objections? If you could email me, I’d appreciate it, so I can know whether to write up the post & demo on my site.

    Cheers ;)

    Fred

  40. February 20, 2010 @ 5:26 pm

    Hey, David,

    Well, I posted it anyway: http://www.skyrocketlabs.com/articles/jquery-social-dropdown-menu.php

    Thanks for the inspiration!

  41. February 27, 2010 @ 2:13 am

    thanks guys, both of ypu. great designers:)

  42. February 27, 2010 @ 3:13 am

    thans guys anyway, at least some of you could tell me “I don’t know “or anything, but anyhow thanks for good lesson learned.

  43. May 4, 2010 @ 10:57 am

    Thanks again David, you nailed it. I am adding a photo gallery and text togglers to one page of a site, the javascripts weren’t cooperating with each other. Once again I turned to your blog for a jQuery alternative and found a better version than what I was using originally. Thanks.

  44. kenn
    May 14, 2010 @ 2:36 pm

    Love it! Exactly what I wanted… and great for my meager skill level. Thanks!

    Ummm… do we know why we can click the white space to the right of the links and have them open? It would be great if that would not be a link over there.

    Any thoughts?

  45. May 14, 2010 @ 3:44 pm

    @Kenn: If you’re using h3/h* tags, the white-space is showing that “pointer” cursor because H tags are blocks. Change their display property to “display:inline;”, add a “>br /<” tag after if, and you’ll be set.

  46. kenn
    May 14, 2010 @ 3:57 pm

    Thanks for the fast reply David. Awesome!

    I shoulda thought of that block vs. inline thing!

    Things stopped working when I did as you suggested… but I am sure I did it too fast. Going to work on it again tomorrow when I have time again. Thanks so much.

  47. brenen
    May 25, 2010 @ 6:05 pm

    Is there any way to make the window scroll to the top of the clicked element? I modified your mootools version to do it on an old site and I was looking to change it to jquery. With mootools I added this:

    onComplete:function(){
    var target = el;
    if (!this.wrapper['offset' + this.layout.capitalize()] == 0) new Fx.Scroll(window).toElement(target);
    }

    How would you do that with jquery?

  48. olof
    June 7, 2010 @ 9:53 am

    Is there a way to get rid of not only the white space that is clickable, as Kenn asked about, but everything “to the right”. If you append background color or a frame to the div (or add another div around each Q) this will expand to be as wide as the screen. I want it to behave as a normal div where I can set a min-width and then let it expand depending on the with of the objects in the div. Is there a way to do this?

  49. matt
    June 29, 2010 @ 10:21 am

    Hey just wanted to know if I can link to a specific FAQ from an email and have that particular FAQ be expanded when page loads? is there anything I can put on the link to tell the script open this FAQ?

    Thanks guys

  50. July 11, 2010 @ 6:29 pm

    Thanks for this. I am using the Elegant code, but why does it jump? Also, in IE8, the h4 tag collapses so there is no spacing after clicking on one of the questions.

    http://www.onlinemathgrade12345.teachmewell.com/faq.asp

  51. August 29, 2010 @ 9:04 pm

    I’ve updated the effect to no longer “jump”. The key is this CSS:

    #faqs { position:relative; }

    Problem solved!

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!