Have Your jQuery Fun on Any Site with Greasemonkey
Quick Tip – Set Hover Class for Anything

Feb 08 2007

More Showing, More Hiding

read 230 comments
by Karl Swedberg

We've received a number of comments recently from people looking for variations on the showing and hiding theme. For the basics, you can take a look at two earlier entries, Basic Show and Hide and Slicker Show and Hide.

For a full-blown plugin solution with lots of options, look no further than Jörn Zaefferer's Accordion Menu. But if you want to try some showing and hiding on your own, read on.

Caveat

In this tutorial, we'll explore a couple ways to show and hide details by clicking on headings. I recognize that there are many ways to mark up the HTML for this sort of thing, and many more ways to write the JavaScript/jQuery. Even the functionality can vary greatly, depending on your needs. Some common variations include:

  1. each detail shows and hides independently of others
  2. one and only one detail visible at a time
  3. either no detail or one detail visible at a time

We'll take a look at the first two variations this time, and the third in a separate entry (so that I can get something posted more quickly).

The Setup

As with any jQuery script, we need to include the jquery.js file and our custom script file in the <head>, like so:

PLAIN TEXT
HTML:
  1. <script src="/js/jquery.js" type="text/javascript"></script>
  2.   <script src="/js/more-show-hide.js" type="text/javascript"></script>

It's important to include jquery.js before any other files that use it. Also, you may need to change the path to match your site's structure.

For the elements to show and hide, we'll use a simple <h3> / <div> structure:

PLAIN TEXT
HTML:
  1. <div class="demo-show">
  2.   <h3>Title 1</h3>
  3.   <div>Lorem...</div>
  4.   <h3>Title 2</h3>
  5.   <div>Ipsum...</div>
  6.   <h3>Title 3</h3>
  7.   <div>Dolor...</div>
  8. </div>

Now let's add to that a little CSS to shape things up a bit:

PLAIN TEXT
CSS:
  1. .demo-show {
  2.   width: 350px;
  3.   margin: 1em .5em;
  4. }
  5. .demo-show h3 {
  6.   margin: 0;
  7.   padding: .25em;
  8.   background: #bfcd93;
  9.   border-top: 1px solid #386785;
  10.   border-bottom: 1px solid #386785;
  11. }
  12. .demo-show div {
  13.   padding: .5em .25em;
  14. }

Finally, we can get to the scripting.

Option 1: Independent

Remember, this is the option that allows each detail section to be shown or hidden independently of the others. It's also the easiest of the three to accomplish.

The key method we'll be using here is .slidetoggle(), an excellent little effect that slides the matching elements down when they are hidden and slides them up when they are visible. But before we do that, let's make all of the detail sections hide when the DOM is ready:

PLAIN TEXT
JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show:eq(0)> div').hide();  
  3. });

Line 2 gets every <div> that is a child of the first <div> and hides them. I'm using :eq(0) here because I'll be showing two show-hide examples that use the same class, but we're taking the examples one at a time.

Now, we can bind a click handler to each <h3> that is a child of <div>. You can see this in line 3 below:

PLAIN TEXT
JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show:eq(0)> div').hide();  
  3.   $('div.demo-show:eq(0)> h3').click(function() { });
  4. });

All that's left is to drop the .slidetoggle() method inside the click method. Since we know that each <div> that we want to toggle appears next to each <h3> that might be clicked, we can use the handy .next() method (line 4):

PLAIN TEXT
JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show:eq(0)> div').hide();  
  3.   $('div.demo-show:eq(0)> h3').click(function() {
  4.     $(this).next().slideToggle('fast');
  5.   });
  6. });

I used the "fast" option for the duration of the slide, but we also could haved used "slow" or "normal" or a numeric value for the number of milliseconds.

Try out the demo. See how a click on each <h3> will show or hide the next <div>, independent of the others:

Title 1

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Title 2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Title 3

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Option 2: One and Only

Let's move on now to the scenario in which we want one detail <div> at all times, but no more than one. The first thing we'll need to change for this one is the line that hides all of the child <div>s of <div>. We'll make it hide all but the first <div>:

PLAIN TEXT
JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show:eq(1)> div:gt(0)').hide();  
  3. });

Again, we add an :eq() to the containing <div> selector, this time with 1 as the index, because we want our second demo (and because JavaScript numbering starts at zero).

Next, we add the same click handler for the <h3> elements, but this time we need to change the effects that take place within it:

PLAIN TEXT
JavaScript:
  1. $(document).ready(function() {
  2.   $('div.demo-show:eq(1)> div:gt(0)').hide();  
  3.   $('div.demo-show:eq(1)> h3').click(function() {
  4.     $(this).next('div:hidden').slideDown('fast')
  5.     .siblings('div:visible').slideUp('fast');
  6.   });
  7. });

Line 4 above slides down the <div> that follows the clicked <h3> by using $(this).next(), but only if that <div> is hidden (:hidden). Also, now that we've chained .next() onto $(this), we've changed the context to that following <div>. So then in line 5 when we refer to .siblings(), we're actually getting the siblings of the <div>. Since out of all the siblings we only want to slide up the slides up the ones that are visible <div>s, we use .siblings('div:visible').

Give demo #2 a whirl:

Title 1

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Title 2

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Title 3

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

There you have it—two fairly straightforward examples of showing and hiding elements on a page. Next time we'll take a look at two ways we can implement the third variation on the showing-and-hiding theme: having either no detail or only one shown at all times.

Scripts included in this post:

  • www.learningjquery.com/js/more-show.js
  • Other JavaScript Files …
comment feed

230 comments

Newer Comments »
  1. CH
    February 8, 2007 at 10:41 am

    Hi.
    Thanks for your tutorials. They are great.

    I have a question. I'm trying to use the same technique to create a mouse over (or click) effect where the text appers the same place but differ according to what button you click (over spot you mouseover). My problem is that if I click/mouseover before the first effect (eg. SlideDown) is finish I get the new text AND the old text (that should be hidden .hide()) right after each other and hence breaking the layout...:(

    Can I somehow tell the slideDown-function to hide everything else even if another slideDown effect is still taking place...?

    Hope it was somewhat clear...;-)

    Reply
  2. Karl
    February 8, 2007 at 2:11 pm

    Hi CH,
    I'm glad you like the tutorials! I think I understand what you're trying to do, but I'm not certain. You might want to try to put the .slideDown() in the callback of the .slideUp(). If you can wait a few days, I'll be posting a follow-up entry that describes how to do that.

    Reply
  3. CH
    February 8, 2007 at 5:52 pm

    Cool. Ill give it a shot tomorrow at work.

    Keep up the great work!

    Reply
  4. Ty
    February 8, 2007 at 11:32 pm

    What do you think about image button's, instead of using text link title 1, title 2, it should be possible right? This would essentially create a drop down, or flyout menu, with several links for each of the three buttons. Sounds workable no... It would be great if the flyout slightly overlapped the button to more appear that it was the flyout from the button.
    I'm not sure I've seen an accordion menu done with image buttons, I guess that would work too, but left to right fly-in was the requested effect. That I've no idea how to accomplish.
    Keep the great stuff coming then jQuery'ers!

    Reply
  5. Karl
    February 9, 2007 at 12:07 pm

    Hey Ty,
    There's no reason it couldn't be done with image buttons. I think I understand what you're getting at with the fly-out menu idea. You would want the fly-out stuff to overlay everything, right?

    Reply
  6. Sean O
    February 9, 2007 at 4:30 pm

    Karl, nice tutorial. Good way to demonstrate some more advanced selectors.

    Also see the Xpander plugin for another take on this:
    labs.activespotlight.net/jQuery/Xpander.html

    _______
    SEAN O

    Reply
  7. Karl
    February 9, 2007 at 11:02 pm

    That's a really cool one. Thanks, Sean!

    Reply
  8. enquest
    February 13, 2007 at 10:18 am

    their is something wrong... Their is a small but sudden flash before the anim. start.

    Reply
  9. Karl
    February 13, 2007 at 10:35 am

    Ah, yes, you're probably using FF2.0 Mac, right? That flicker is due to a bug in an early 1.1.1 build of jquery.js. I just updated to a more recent SVN build and tested it; I don't see the flicker now.

    Thank you for bringing this to my attention! Would you mind testing it again and seeing if the flicker still occurs?

    Reply
  10. rolfsf
    February 24, 2007 at 12:44 pm

    thanks Karl
    one question about this demo - what does the "gt" in div:gt(0) mean or do? or is that "greater than"?

    Also, and this may be outside the scope of this demo, if you had 3 divs stacked, how would you modify this script so that at any one time only 2 divs (at most two) could be open, with the third closing itself?

    Reply
  11. rolfsf
    February 24, 2007 at 12:58 pm

    hmm... the more I think about what I just asked, the more potential problems I see, but the idea was that two adjacent divs would be visible (1 & 2 or 2 & 3). Thanks!

    Reply
  12. Karl
    February 24, 2007 at 2:50 pm

    Hi Rolf,
    You're correct about div:gt(0). It gets all divs that have an index greater than 0, or, in other words, all divs after the first one.

    About the 2-visible, 1-hidden idea — unfortunately, it is outside the scope of this demo. If you know there will be only three total div, though, you could easily do it by setting one .click() handler for $('h3:eq(0)') and another one for $('h3:gt(0)'). Hope that helps point you in the right direction.

    Reply
  13. Philip
    March 10, 2007 at 11:15 am

    Hi Karl,
    In your example here, when I hover over the h3 titles I see a little hand icon that indicates I can click on them as if they were links. On my pages I only see a caret.
    What do I do to show those hand icons?
    Thanks!

    Reply
  14. Philip
    March 10, 2007 at 11:34 am

    Well Karl... I just found the answer to my question by reading your next article...
    :-)
    Thanks all the same.

    Reply
  15. Karl
    March 10, 2007 at 7:37 pm

    Hey Philip,

    Glad to see that you found what you were looking for. Cheers!

    Reply
  16. Rob Callahan
    March 15, 2007 at 2:18 pm

    Hi,

    I can't seem to get the following to work:

    $('input[@type=checkbox]').each(function(i) {
    this.hide();
    });

    or

    $('input[@type=checkbox]').each().hide();

    Are there limita

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.