Fancy FAQs with jQuery Sliders

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!


Comments

  1. Alex Crooks

    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. David Walsh

    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?

    • Armin Medić

      u can handle that jump with tag instead tag, it works fine

    • Armin Medić

      with instead sorry for the upper reply hah

    • Armin Medić

      woooot!!!! i mean BR tag insted P tag damit

  3. Alex Crooks

    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. Mohamed Jama

    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. Chris Coyier

    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. David Walsh

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

  7. David Walsh

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

  8. Guido

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

  9. xeon

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

  10. David Walsh

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

  11. Vinícius Borriello

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

    @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. David Walsh

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

  14. Steve Vetzal

    Nice post…

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

  15. Steve Vetzal

    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

    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. Douglas Neiner

    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

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

  19. Rodrigo Flore

    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

    hmmmm I prefer the mootools effect

  21. daniele

    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

    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. Chris the Developer

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

  24. Darkimmortal

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

    It even happens on the jQuery homepage demo D:

  25. Douglas Neiner

    @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. Ralph Whitbeck

    @Douglas Neiner: It’s all fixed.

  27. Zy

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

  28. Douglas Neiner

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

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

  30. Elving

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

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

  32. Skyrocket Labs

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

  33. Abid Din

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

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

    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

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

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

  38. Ranjan Datta

    Here is my stab at FAQs.

    I used definition list for markup

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

  39. Skyrocket Labs

    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. Skyrocket Labs

    Hey, David,

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

    Thanks for the inspiration!

  41. Vladdy

    thanks guys, both of ypu. great designers:)

  42. Vladdy

    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. Bill Lord

    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

    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. David Walsh

    @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

    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

    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

    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

    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

    • Bruce

      Does anyone have a solution for this, so an external link can anchor to a specific question and expand it automatically?

    • Matt

      I’m guessing this can be done by passing some variable in the url? I don’t know exactly. I asked this question June 2010.

  50. Jason S.

    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. David Walsh

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

    #faqs { position:relative; }

    Problem solved!

  52. Cintia

    Hi David,

    I never comment, but I love your website!

    I am having problems with my FAQ list. It has more than 17 questions, when I add the 18th, the page goes blank, it doesn’t show any of the previous questions that were in there. Is there a problem with using more than one within a ? This is a WordPress website BTW.

    Any ideas why this is happening?

    Thanks!

  53. Cintia

    I have to fix my comment, the tags aren’t showing up. I meant:
    I am having problems with my FAQ list. It has more than 17 questions, when I add the 18th, the page goes blank, it doesn’t show any of the previous questions that were in there. Is there a problem with using more than one within a
    ? This is a WordPress website BTW.

    Any ideas why this is happening?

    Thanks!

  54. Cintia

    More than one P tag within a DIV…….

    • David Walsh

      More than one P element shouldn’t cause any problems.

  55. zef

    how do you make it so that only one answer shows up at any given time?

  56. tyler k

    Is the effect slightly jerky for anyone using FF as opposed to IE or Chrome? It is for me at least. See the bottom of page with FAQ: here and a another implementation: here

  57. Cintia

    I’m again using your fantastic code (thanks), but I’m having a compatibility problem. I have a slider going on in a separate page, and the script for this slider is:

    $(document).ready(
    function(){
    $('ul#portfolio').innerfade({
    speed: 1000,
    timeout: 5000,
    type: 'sequence',
    containerheight: '130px',
    slide_timer_on: 'yes',
    slide_ui_parent: 'portfolio',
    slide_ui_text: 'portfolio-desc',
    pause_button_id: 'pause_button',
    slide_nav_id: 'slide_nav'
    });
    $.setOptionsButtonEvent();

    $("#pause_button").click(function() {
    $.pause();
    });
    $("#next_button").click(function() {
    $.next();
    });

    $("#prev_button").click(function() {
    $.prev();
    });

    $("#first_button").click(function() {
    $.first();
    });

    $("#last_button").click(function() {
    $.last();
    });

    });

    When I disable this script, the FAQ slider works perfectly. If it’s enable, the FAQ won’t work. Any ideas why?
    Thank you!

  58. Harry Fear

    Wonderful code!!

    How can I make the script collapse all FAQs before opening the demanded one. I want one to be visible at any one time!

    Thanks! :)

  59. Harry Fear

    Have answered my own question:

    $(document).ready(function() {
    $('#faqs h3').each(function() {
    var tis = $(this),
    state = false,
    answerNext = tis.next('div').hide().css('height','auto').slideUp();
    answerAll = $('#faqs').children('div').hide().css('height','auto').slideUp();
    tis.click(function() {
    state = !state;
    answerAll.slideUp(state);
    $('#faqs').children('h3').removeClass('active');
    answerNext.slideToggle(state);
    tis.addClass('active',state);
    });
    });
    });

    • PeterV

      This is all fantastic – as a complete noob it’s like magic to me ;-)

      However… with your new version, Harry, it does a strange thing if you click on the FAQ’s title that is currently showing – ie, it hides the FAQ and then immediately shows it again, which looks a little odd.

      Do you know how to make sure that the FAQ stays hidden?

      Cheers

  60. Bobby

    Any solution yet on IE8 bug? When a question is clicked, all the padding or margins below it are gone, like Jason S above have said.

  61. Phil

    Great tutorial. Like Harry Fear, I’m trying to make it so that only one FAQ shows at a time. I tried his code, but as PeterV commented, if you click the one that is already opens, it just re-opens it. Any ideas on how to fix this?

  62. Joseph

    Hey… I know there’s probably a more elegant way to do this but I added a little tag before the FAQ to override the hight and overflow properties to display content when JavaScript is disabled:

    #faqs div {height:auto;overflow:visible}

  63. Vsagar

    How can I use this in my WordPress site?
    When I create a new page, I can paste the following text in my page editor in html view -
    This is question 1?
    This is the answer to question #1.
    This is question 2?
    This is the answer to question #2.

    But where to put that javascript code?
    When I tried putting it in the same page in html view, it is simply discarded by WP editor, when the page is published.

  64. Denis Lam

    Hello, the codes seems to work for jQuery 1.4.1 but it doesn’t work for 1.6.1. Does anyone else experience this? Is there any updated code compatible with 1.6.1?

  65. VSagar

    Is this site dumb…
    Why don’t you answer, since long I had put one comment….
    Since then no reply….
    Please help…

  66. VectorPile

    Nice script! I’ve been experiencing problems with the jagged animation on my page and finally came to realize that it was due to ‘box-shadow’ element on my page container. I still haven’t found a fix for it, but simply removing it makes it smooth like in the demo.


Be Heard!

Share your thoughts without being a jerk! And wrap your code in <code> tags, f00!

Name*:
Email*:
Website: