How to Build a Horizontal jQuery Accordion

How to Build a Horizontal jQuery Accordion

Sliders, accordions oh my!

If you search for jQuery slider, you will find tons of posts and articles on how to do so. There are plenty of ways of building one, and I haven’t really seen any two that were exactly the same. Hell, even I wrote on how to build a jQuery slider, using the slider on this blog as an example. You know what is quite difficult to find though? Tutorials on horizontal accordions. I had a hell of a time figuring out how, because most of the articles are about using a plugin. Which, if you have read any of my posts in the past, you will know that I like to do things myself most of the time. I only found one that was super helpful, and it was buried a few pages in. The only problem is that it was using an unordered list, and I needed it to use divs. Luckily for me it was easy to change, and if you care to view the original tutorial over at Design Chemical (written by a guy named Lee I believe), please do so and tell him he rocks. Take a look at the demo first so you can see what the end result looks like.

View Demo

First things first – the HTML

Let me first state that the there is an issue with IE7 with the HTML/CSS. The Javascript works fine, but the image is too far over. I will post the corrections for it later, I just wanted to get the post up for you since it has been a while since I have written anything.

Note: I am only showing one panel below, but I am using 4. You can see the all of them if you view the source in the demo

<div id="accordion">
    <div class="panel">
      <div class="pink"></div>
      <div class="panelContent p1"> <strong>Section 1 Header</strong><br/>
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. In iaculis volutpat quam, non suscipit arcu accumsan at. Aliquam pellentesque.
      </div>
</div>

As you can see, there is not much there. If you looked at the demo, you will see what is going on in the above HTML. A wrapper (‘#accordion’), a div for each little pink section (.’pink’), a div for each individual panel (‘.panel’), and the content within – pretty easy stuff.

The styles

Again, not much going on with the styles. Below is the important stuff, which doesn’t include the classes that call the individual pink bar images.

#accordion {
	list-style:none;
	margin:30px 0;
	padding:0;
	height:270px;
	width:980px;
	margin:0 0 0 11px;
	border-top:2px solid #000000;
	border-bottom:2px solid #000000;
	overflow:hidden;
}
#accordion .panel {
	float:left;
	display:block;
	height:270px;
	width:44px;
	overflow:hidden;
	color:#666666;
	text-decoration:none;
	font-size:16px;
	line-height:1.5em
}
#accordion .panel.active {
	width:848px
}
.panelContent {
	padding:15px 15px 15px 55px;
	height:240px;
	width:778px;
}
.pink {
	width:42px;
	height:270px;
	float:left;
	background:url(../images/accordionSprite.png) no-repeat 4px 85px #f980a1;
	border-right:2px solid #ffffff;
	cursor:pointer
}
.last {
	border:none
}

Some things to note about the CSS. My total width is 980px. The reason the active panel (the one showing) is 848px is because there are 4 panels, 3 of which are closed and each of them have a total width of 44px. So 980 – (44 x 3) = 848px. It is 44px because the width is 42px plus a two pixel border. See, there is some math you have to do to get everything to fit correctly. Make sure you are paying attention to that when you are building your own.

jQuery please!

Now on to what you really wanted to see, right? I’ll explain what is happening below.

$(document).ready(function(){
 
    activePanel = $("#accordion div.panel:first");
    $(activePanel).addClass('active');
 
    $("#accordion").delegate('.panel', 'click', function(e){
        if( ! $(this).is('.active') ){
			$(activePanel).animate({width: "44px"}, 300);
			$(this).animate({width: "848px"}, 300);
			$('#accordion .panel').removeClass('active');
			$(this).addClass('active');
			activePanel = this;
		 };
    });
});

Once again, not a heck of a lot of code to get this thing going. The first two lines, after the document ready thing of course, is for getting the first panel within the wrapper (‘#accordion’), and giving it a class of ‘active’. All that class does is change the width from 44px to 848px. Whichever panel has the ‘active’ class is the one that is showing.

Next comes the click function, which I am using delegate() for so that there is only one event handler, rather than one for each panel. Then the script checks to see if the panel click is NOT the active one, and if it isn’t, animate the active one’s width down to 44px, with the animation time set to 300. Then animate the panel that was clicked, so that it’s width becomes 848px, at the same speed.

After that, it removes the ‘active’ class from all of the panels, and adds the class back to the one that was clicked. The last line then makes the ‘activePanel’ variable be the panel that was clicked.

One last note. I did have the following in place of the 300 speed, but it didn’t seem to need it, so I took it out. It clears the animation queue, but I think the accordion moves so fast that it doesn’t seem to matter if it is in the script.

$(activePanel).animate({width: "44px"}, {duration:300, queue:false});
$(this).animate({width: "848px"}, {duration:300, queue:false});

Conclusion

I am using this exact script in a freelance project I am working on (which I will show you guys when it’s done), and I am pretty happy with it. Again, I have to change the HTML and CSS around because of IE7′s issue, but the script itself works great in 7 or 8. Didn’t check IE6 because I don’t really care anymore unless someone specifically asks for it to be supported.

Let me know what you think, and leave a comment!

Coupon Code: webmachine

Tags: , , ,

21 Responses to “How to Build a Horizontal jQuery Accordion”

  1. Liam says:

    Hi,

    Thanks for your post. This is exactly what I am looking for.
    Was wondering if you fixed the IE error.

    This looks perfect.

    Thanks,

    Liam

    • jcDesigns says:

      Actually I think I had already fixed whatever the problem was. I just looked at it in IE7 and I don’t see anything glaring. If you do, please let me know.

      • Jean says:

        Hi,

        in IE7 the content of each active panel does not display? Is this a z-index issue perhaps or something else?

        Thanks

  2. Paul J. Adam says:

    Thanks for the great tutorial/demo. Everything was going great until I tried it in IE7 & IE9 where it fails :(

    REALLY HATE INTERNET EXPLORER!

  3. Paul J. Adam says:

    Wait, I’m wrong it DOES work on IE 9, I was using IE tester first and just upgraded to IE9 on my windows VM and it works fine there. Sorry about that.

  4. Tim Hunter says:

    Is there a way to add vertical text to the 44px-wide panels? Essentially, they would have a label. Thanks.

    • jcDesigns says:

      Yes, indeed there is. you can go to http://www.closetfish.com to see that in action.

      Here is the solution for that.

      .titleRotate {
        color: #ffffff;
        font-family: Tandelle, Arial,Helvetica,sans-serif;
        font-size: 20px;
        font-weight: normal;
        position: absolute;
        top: 202px;
        text-align: right;
        left: -184px;
        width: 408px;
        height: 24px;
        overflow: hidden;
        letter-spacing: 2px;
        -webkit-transform: rotate(-90deg);
        -moz-transform: rotate(-90deg);
        -ms-transform: rotate(-90deg);
        -o-transform: rotate(-90deg);
      }
       
      .ie8 .titleRotate, .ie7 .titleRotate {
        left: 10px;
        top: 15px;
        f
  5. gegi says:

    Thanks for your tutorial. I have one problem, i want that the active panel at loading was last, how can i do that?

  6. Steve says:

    This is a site we are working on the panel seems to jog left when clicked, any ideas what may make this happen? have tried changing widths in java script and css. any Ideas would be appreciated Thanks

    • jcDesigns says:

      I don’t have time to dive into your code, but that looks like a simple case of bad math. Adding up all the widths/padding on the divs within .panel = 782, while .panel is 784. I suggest going through your math again.

  7. Jane says:

    Hi. Enjoyed spending far too long getting the hang of this! Just having a problem: I want the first panel to be open on load, but this is not happening. I’m not sure if I messed something up, or what to do. Also, the links at the bottom have gone weird. I would really appreciate your input!
    Thanks!

    • jcDesigns says:

      You forgot to add any css to the .active class, which changes the width of the active panel. Your first panel is selected, but width change makes it look closed.

      • Jane says:

        Thanks for that – there was an error in the CSS, and I have given the .active its own CSS also. Still unsure why the footer should look different on this page, but very, very grateful for your help!

    • jcDesigns says:

      Look at your footer ul. On the page that has the accordion, it is getting different styles from the accordion stylesheet. I’m not sure what is going on without diving into it, but if you put clear: both on the .footer class, your footer nav will look the same as the other pages, just further down.

      • Jane says:

        Thanks. I’ve fixed it – the size of the various containers was pushing into the footer and pushing the text over, so I have increased the height and it has fixed it.

        Now trying to make it work in a tablet and mobile viewport. Is there a way of altering the script to recognize the device, and therefore restrict the width? I think the issue is “$(this).animate({width: “750px”}, 300);” – it seems to be over-riding the narrower width I am setting for .panel .active and/or .active.

        Thanks again. Really admiring what you’ve done to get this working! (I’ve also credited you in the CSS – thanks.)

      • Jane says:

        Ps It seems to work using % instead of width. I’ll let you know the progress – currently attempting 84% as the panels disappear off the page otherwise.

  8. Carl says:

    Hi.
    Thank you for the great slider!
    One question: would it be possible to have them open on hover?
    If so, any chance you might be able to explain how?

    • jcDesigns says:

      I am pretty sure that if you change the ‘click’ in the function to ‘hover’, it would work. The problem I see with this is that the panels you click are very close together and you could end up with this thing sliding all over the place due to your mouse position. I wouldn’t recommend it, but let me know if you do and what happened.

  9. Brandon says:

    Thanks so much for the tutorial! I had been trying to build something like this for a few days but could not find anything useful until yours.

    One question: how can I change the js so that all of the panels are closed on load?

    Thanks a lot!

  10. Michal says:

    Hello! Thanks for the tutorial, it’s way better than every plugins I used so far. The one thing I miss is the URL. Is there any option after clicking the url would change e.g. to #contact, #about? And if someone enters url http://www.page.com/#gallery it will display the #gallery as active slide?

    thanks in advance!

Leave a Reply