• home
  • forum
  • my
  • kt
  • download
  • How to Create a Custom jQuery Accordion

    Author: 2009-04-17 08:09:05 From:

    Accordions can be very useful for showing lots of different sections of data in a small amount of space. jQuery UI has a built in Accordion function, but according to the jQuery UI Build your Download, the size of the Core jQuery UI and Accordion scripts are 25kb and 16.6kb, respectively. Today, I'll show you how to build a custom accordion that is more "bandwidth efficient".

    That seems like a lot for just one simple accordion. Especially when you add in the normal jQuery script, which is 18kb minified and Gzipped. So instead of increasing your page load time with the extra unneeded functionality, why not create something from scratch?

    I also think that writing things from scratch really gives you a much better understand of how to use jQuery effectively, without always turning to use someone else’s code.

    So the plan for this tutorial is to show create an accordion using the jQuery UI function, then create one using some custom coding. Let’s use a blog sidebar as an example.

    The Markup

    The markup is very simple, just a list item for each section in the accordion:

    view plaincopy to clipboardprint?
    1. <ul id="accordion">  
    2.     <li>  
    3.         <a href="#recent" class="heading">Recent Entries</a>  
    4.         <ul id="recent">  
    5.             <li><span class="date">01.19.2009</span> <a href="#">Recent Entry Title</a></li>  
    6.             <li><span class="date">01.15.2009</span> <a href="#">Recent Entry Title</a></li>  
    7.             <li><span class="date">01.13.2009</span> <a href="#">Recent Entry Title</a></li>  
    8.             <li><span class="date">01.11.2009</span> <a href="#">Recent Entry Title</a></li>  
    9.             <li><span class="date">01.10.2009</span> <a href="#">Recent Entry Title</a></li>  
    10.         </ul>  
    11.     </li>  
    12.     <li>  
    13.         <a href="#popular" class="heading">Popular Entries</a>  
    14.         <ul id="popular">  
    15.             <li><span class="date">08.16.2008</span> <a href="#">Popular Entry Title</a></li>  
    16.             <li><span class="date">06.12.2008</span> <a href="#">Popular Entry Title</a></li>  
    17.             <li><span class="date">04.12.2008</span> <a href="#">Popular Entry Title</a></li>  
    18.             <li><span class="date">06.12.2007</span> <a href="#">Popular Entry Title</a></li>  
    19.             <li><span class="date">03.12.2007</span> <a href="#">Popular Entry Title</a></li>  
    20.         </ul>  
    21.     </li>  
    22.     <li>  
    23.         <a href="#categories" class="heading">Categories</a>  
    24.         <ul id="categories">  
    25.             <li><a href="#">Category Name</a> <span class="count">7</span></li>  
    26.             <li><a href="#">Category Name</a> <span class="count">4</span></li>  
    27.             <li><a href="#">Category Name</a> <span class="count">15</span></li>  
    28.             <li><a href="#">Category Name</a> <span class="count">29</span></li>  
    29.             <li><a href="#">Category Name</a> <span class="count">8</span></li>  
    30.         </ul>  
    31.     </li>  
    32.     <li>  
    33.         <a href="#archive" class="heading">Archive</a>  
    34.         <ul id="archive">  
    35.             <li><a href="#">January 2009</a> <span class="count">4</span></li>  
    36.             <li><a href="#">December 2008</a> <span class="count">14</span></li>  
    37.             <li><a href="#">November 2008</a> <span class="count">12</span></li>  
    38.             <li><a href="#">October 2008</a> <span class="count">8</span></li>  
    39.             <li><a href="#">September 2008</a> <span class="count">18</span></li>  
    40.         </ul>  
    41.     </li>  
    42. </ul>  

    The CSS

    We are going to add some very basic styling so that the accordion looks more presentable. Since this tutorial is mainly focused on the JavaScript, I am going to run through what we are doing with the CSS quickly.

    Since I always start from my own simple framework stylesheet, I’m going to use it here too:

    view plaincopy to clipboardprint?
    1. /*****Reset*****/  
    2. html, body, div, h1, h3, h3, h4, h5, h6, ul, ol, dl, li, dt, dd, p, blockquote, pre, form, fieldset, table, th, td { margin: 0; padding: 0; }   
    3.   
    4. /*****Basic Definitions*****/  
    5. body { background#fffcolor#333font14px/20px Georgia, "Times New Roman", Times, serif; }   
    6. h1 { font-size24pxline-height30pxmargin-bottom18px; }   
    7.   
    8. a { }   
    9. a:visited { }   
    10. a:hover { text-decorationnone; }   
    11. img { bordernone; }   
    12. p, ul, ol, dl, table { margin-bottom18px; }   
    13. ul, ol, dd { margin-left36px; }   
    14.   
    15. /*****Custom Classes*****/  
    16. .clearing { clearboth; }   
    17. .clearfix { overflowhidden; }   
    18. .last { margin-bottom: 0; }   
    19. .screenReader { left: -9999pxpositionabsolutetop: -9999px; }  

    Next, I am going to remove the margin and list-style from the accordion unordered list and the descendant lists and add a bottom border to the accordion unordered list (you will see why it is only a bottom border shortly).

    view plaincopy to clipboardprint?
    1. ul#accordion, ul#accordion ul { list-stylenonemargin: 0; }   
    2. ul#accordion { border-bottom1px solid #000E2E; }  

    Then, I am going to add a border around each accordion section, except the bottom border. Also, I am going to remove the border from list items that are descendants of the accordion section and add only a bottom border. If it is the last child of a descendant unordered list, I am going to remove the bottom border. Yes, I know this will not work in IE, but it’s not essential.

    view plaincopy to clipboardprint?
    1. ul#accordion li { border1px solid #000E2Eborder-bottomnone; }   
    2. ul#accordion ul li {    
    3.     bordernone;   
    4.     border-bottom1px solid #C2C8D1;   
    5.     color#999;   
    6.     padding5px 10px;   
    7. }   
    8. ul#accordion ul li:last-child { border-bottomnone; }  

    Next, I am going to style the main link that will toggle the accordion so that they stand out more:

    view plaincopy to clipboardprint?
    1. ul#accordion a.heading {    
    2.     background#F4FFF9;   
    3.     color#999;   
    4.     displayblock;   
    5.     font-size18px;   
    6.     line-height18px;   
    7.     padding10px 5px;   
    8.     text-decorationnone;   
    9. }   
    10. ul#accordion a.heading:hover { background#00B9D2color#fff; }  

    Finally, I am just going to do some basic styling on the sub lists of the accordion so that they look a little nicer:

    view plaincopy to clipboardprint?
    1. ul#accordion li ul a { border-bottom1px solid #00B9D2color#025185text-decorationnone; }   
    2. ul#accordion li ul a:hover { border-bottomnone; }   
    3. ul#accordion li ul .date { padding-right10px; }   
    4. ul#accordion li ul .count { padding-left10px; }  

    Let’s take a look at where we are so far. This is also what the accordion will look like when we are using the jQuery UI Accordion and JavaScript is disabled.

    Accordion Markup

    It looks like we will need to add some additional CSS for IE6 to account for the whitespace bug:

    view plaincopy to clipboardprint?
    1. ul#accordion { floatleftwidth300px; }   
    2. ul#accordion li { floatleftwidth298px; }   
    3. ul#accordion a.heading { width298px; }   
    4. ul#accordion ul li { floatnonewidthauto; }  

    The jQuery UI Accordion

    jQuery UI Home Page

    Now that we’ve got all the markup and styling complete, it is very simple to implement the jQuery UI accordion. First, we just need to include jQuery and our jQuery UI script.

    view plaincopy to clipboardprint?
    1. <script type="text/javascript" src="scripts/jquery.js"></script>  
    2. <script type="text/javascript" src="scripts/jquery-ui-accordion.js"></script>  

    Then, we need to initialize the accordion on our unordered list with an id of accordion:

    view plaincopy to clipboardprint?
    1. <script type="text/javascript">   
    2.     $(document).ready(function() {   
    3.         $('#accordion').accordion();   
    4.     });   
    5. </script>  

    And there you have it, a working accordion.

    Working Accordion

    To make the currently open accordion item stand out more, I added a little extra CSS:

    view plaincopy to clipboardprint?
    1. ul#accordion li.ui-accordion-selected a.heading { background#025185color#fff; }  

    The class name of ui-accordion-selected is automatically added to the current accordion section.

    Our Custom jQuery Accordion

    Now that we have done the jQuery UI accordion, it’s time to create our own. One thing that I don’t necessarily like about the jQuery UI version is the way it displays when JavaScript is disabled. I would prefer to have it so that only one section is open at a time.

    To accomplish this, I am going to add in a little PHP. You could easily accomplish this with any programming language as well.

    The idea behind this is that we are going to pass a variable in the URL, and if the variable coincides with each section, we assign a class of current to that section. It is much easier to see this in code, so have a look:

    view plaincopy to clipboardprint?
    1. <?php $section = $_GET['section']; ?>   
    2. <ul id="accordion">   
    3.     <li<?php if($section == '' || $section == 'recent'): ?> class="current"<?php endif; ?>>   
    4.         <a href="?section=recent" class="heading">Recent Entries</a>   
    5.         <ul id="recent">   
    6.             <li><span class="date">01.19.2009</span> <a href="#">Recent Entry Title</a></li>   
    7.             <li><span class="date">01.15.2009</span> <a href="#">Recent Entry Title</a></li>   
    8.             <li><span class="date">01.13.2009</span> <a href="#">Recent Entry Title</a></li>   
    9.             <li><span class="date">01.11.2009</span> <a href="#">Recent Entry Title</a></li>   
    10.             <li><span class="date">01.10.2009</span> <a href="#">Recent Entry Title</a></li>   
    11.         </ul>   
    12.     </li>   
    13.     <li<?php if($section == 'popular'): ?> class="current"<?php endif; ?>>   
    14.         <a href="?section=popular" class="heading">Popular Entries</a>   
    15.         <ul id="popular">   
    16.             <li><span class="date">08.16.2008</span> <a href="#">Popular Entry Title</a></li>   
    17.             <li><span class="date">06.12.2008</span> <a href="#">Popular Entry Title</a></li>   
    18.             <li><span class="date">04.12.2008</span> <a href="#">Popular Entry Title</a></li>   
    19.             <li><span class="date">06.12.2007</span> <a href="#">Popular Entry Title</a></li>   
    20.             <li><span class="date">03.12.2007</span> <a href="#">Popular Entry Title</a></li>   
    21.         </ul>   
    22.     </li>   
    23.     <li<?php if($section == 'categories'): ?> class="current"<?php endif; ?>>   
    24.         <a href="?section=categories" class="heading">Categories</a>   
    25.         <ul id="categories">   
    26.             <li><a href="#">Category Name</a> <span class="count">7</span></li>   
    27.             <li><a href="#">Category Name</a> <span class="count">4</span></li>   
    28.             <li><a href="#">Category Name</a> <span class="count">15</span></li>   
    29.             <li><a href="#">Category Name</a> <span class="count">29</span></li>   
    30.             <li><a href="#">Category Name</a> <span class="count">8</span></li>   
    31.         </ul>   
    32.     </li>   
    33.     <li<?php if($section == 'archive'): ?> class="current"<?php endif; ?>>   
    34.         <a href="?section=archive" class="heading">Archive</a>   
    35.         <ul id="archive">   
    36.             <li><a href="#">January 2009</a> <span class="count">4</span></li>   
    37.             <li><a href="#">December 2008</a> <span class="count">14</span></li>   
    38.             <li><a href="#">November 2008</a> <span class="count">12</span></li>   
    39.             <li><a href="#">October 2008</a> <span class="count">8</span></li>   
    40.             <li><a href="#">September 2008</a> <span class="count">18</span></li>   
    41.         </ul>   
    42.     </li>   
    43. </ul>  

    You should also notice that I changed the url of each of the links the toggle the accordion sections to match up with the if statement for the section. So basically, if JavaScript is disabled, you will be taken to a new page with that section open.

    We also need to remove the jQuery UI accordion script, and include our own:

    view plaincopy to clipboardprint?
    1. <script type="text/javascript" src="scripts/accordion.js"></script>  

    Additional CSS

    With this slight change to the markup, we need to add in a little additional CSS. We no longer have the ui-accordion-selected class being assigned to the list items; it is now a class of current. We also have to account for this class name change in the on state for the accordion:

    view plaincopy to clipboardprint?
    1. ul#accordion li.current a.heading { background#025185color#fff; }  

    So what we want to do is hide all of the unordered lists, unless they are a descendant of the list item with a class of current. I have also added a body id to this demo page so that we can use the same stylesheet for both examples.

    view plaincopy to clipboardprint?
    1. body#customAccordion ul#accordion li ul { displaynone; }   
    2. body#customAccordion ul#accordion li.current ul { displayblock; }  

    The Custom JavaScript

    First, we want to execute the script once the document is loaded, so we start with this:

    view plaincopy to clipboardprint?
    1. $(document).ready(function() {   
    2.   
    3. });  

    We want the accordion to function when the heading links are clicked, but we don’t want to leave the page so we need to make sure and return false:

    view plaincopy to clipboardprint?
    1. $(document).ready(function() {   
    2.     <STRONG>$('ul#accordion a.heading').click(function() {   
    3.         return false;   
    4.     });</STRONG>   
    5. });  

    Next, I don’t like the outline that shows up around the links when they are clicked, so I set that to none:

    view plaincopy to clipboardprint?
    1. $(document).ready(function() {   
    2.     $('ul#accordion a.heading').click(function() {   
    3.         <STRONG>$(this).css('outline','none');</STRONG>   
    4.         return false;   
    5.     });   
    6. });  

    There are two different cases for this script.

    1. The link being clicked is the section that is already open.
    2. The link being clicked is not the section that is already open.

    The First Case

    This is not functionality that the jQuery UI version has, but I think a user should be able to close all sections if they want. If the link clicked has a parent that has a class of current, we want to slide up the unordered list and remove the class of current.

    view plaincopy to clipboardprint?
    1. $(document).ready(function() {   
    2.     $('ul#accordion a.heading').click(function() {   
    3.         $(this).css('outline','none');   
    4.         <STRONG>if($(this).parent().hasClass('current')) {   
    5.             $(this).siblings('ul').slideUp('slow',function() {   
    6.                 $(this).parent().removeClass('current');   
    7.             });   
    8.         }</STRONG>   
    9.         return false;   
    10.     });   
    11. });  

    Another thing that bugs me about the jQuery UI version, is that you can scroll the accordion so it is almost out of view, click it, and then the interaction happens above what you can see. Scroll down on the jQuery UI example and give it a try.

    So my solution is to use this wonderful little script called jQuery ScrollTo. It is a very small script that adds smooth page scrolling.

    Let’s add that to the head of the document before our accordion script:

    view plaincopy to clipboardprint?
    1. <script type="text/javascript" src="scripts/jquery.js"></script>  
    2. <script type="text/javascript" src="scripts/jquery-scrollTo.js"></script>  
    3. <script type="text/javascript" src="scripts/accordion.js"></script>  

    When the section scrolls up, I want to scroll the window to the top of the accordion:

    view plaincopy to clipboardprint?
    1. $(document).ready(function() {   
    2.     $('ul#accordion a.heading').click(function() {   
    3.         $(this).css('outline','none');   
    4.         if($(this).parent().hasClass('current')) {   
    5.             $(this).siblings('ul').slideUp('slow',function() {   
    6.                 $(this).parent().removeClass('current');   
    7.                 <STRONG>$.scrollTo('#accordion',1000);</STRONG>   
    8.             });   
    9.         }   
    10.         return false;   
    11.     });   
    12. });  

    The first parameter of the function is the target to scroll to, and the second is the amount of time it should take.

    The Second Case

    This case occurs when the section that is clicking is not currently open. So the first thing we want to do is hide the currently open section and remove the class of current (this piece of the code is very similar to the first case):

    view plaincopy to clipboardprint?
    1. $(document).ready(function() {   
    2.     $('ul#accordion a.heading').click(function() {   
    3.         $(this).css('outline','none');   
    4.         if($(this).parent().hasClass('current')) {   
    5.             $(this).siblings('ul').slideUp('slow',function() {   
    6.                 $(this).parent().removeClass('current');   
    7.                 $.scrollTo('#accordion',1000);   
    8.             });   
    9.         } else {   
    10.             <STRONG>$('ul#accordion li.current ul').slideUp('slow',function() {   
    11.                 $(this).parent().removeClass('current');   
    12.             });</STRONG>   
    13.         }   
    14.         return false;   
    15.     });   
    16. });  

    Next, we want to open the section we clicked and add the class of current:

    view plaincopy to clipboardprint?
    1. $(document).ready(function() {   
    2.     $('ul#accordion a.heading').click(function() {   
    3.         $(this).css('outline','none');   
    4.         if($(this).parent().hasClass('current')) {   
    5.             $(this).siblings('ul').slideUp('slow',function() {   
    6.                 $(this).parent().removeClass('current');   
    7.                 $.scrollTo('#accordion',1000);   
    8.             });   
    9.         } else {   
    10.             $('ul#accordion li.current ul').slideUp('slow',function() {   
    11.                 $(this).parent().removeClass('current');   
    12.             });   
    13.             <STRONG>$(this).siblings('ul').slideToggle('slow',function() {   
    14.                 $(this).parent().toggleClass('current');   
    15.             });</STRONG>   
    16.         }   
    17.         return false;   
    18.     });   
    19. });  

    Finally, let’s scroll the window to the top of the accordion, just like we did in the first case:

    view plaincopy to clipboardprint?
    1. $(document).ready(function() {   
    2.     $('ul#accordion a.heading').click(function() {   
    3.         $(this).css('outline','none');   
    4.         if($(this).parent().hasClass('current')) {   
    5.             $(this).siblings('ul').slideUp('slow',function() {   
    6.                 $(this).parent().removeClass('current');   
    7.                 $.scrollTo('#accordion',1000);   
    8.             });   
    9.         } else {   
    10.             $('ul#accordion li.current ul').slideUp('slow',function() {   
    11.                 $(this).parent().removeClass('current');   
    12.             });   
    13.             $(this).siblings('ul').slideToggle('slow',function() {   
    14.                 $(this).parent().toggleClass('current');   
    15.             });   
    16.             <STRONG>$.scrollTo('#accordion',1000);</STRONG>   
    17.         }   
    18.         return false;   
    19.     });   
    20. });  

    Take a look at our custom jQuery accordion.

    That’s it. Seriously. Did you think creating an accordion could be that simple?

    Conclusion

    Now, let’s compare the JavaScript file sizes using the Net tab in Firebug.

    Firebug

    In the jQuery UI example, the JavaScript files total about 73 kb. In our custom example, with the additional scrolling of the window, the JavaScript files total about 57 kb. Now, that may not seem like much, but imagine if you have a very high traffic site. That could be a lot of bytes saved. Plus, now you understand more about jQuery.

    discuss this topic to forum

    relation tutorial

    No information

    Category

      AJAX (67)
      Content Management (12)
      Cookies (6)
      Date and Time (17)
      Development (18)
      DHTML (23)
      Forms (10)
      Frequently Asked Questions (3)
      Image Display (14)
      Introduction to Javascript (11)
      Links and Buttons (8)
      Menus (2)
      Miscellaneous (24)
      Mouse Tricks (3)
      Navigation (13)
      Randomizing (6)
      Security (5)
      Text Effects (10)
      User Authentication (2)
      User Information (5)
      Windows and Frames (9)

    New

    Hot