Accordion Tables with Jquery

by Jonathan | Jul 17, 2009 at 9:00 am | Featured, tutorial, web design

Heading

This idea of collapsing tables came to me while trying to retrofit a Lotus Domino web application with better usability. The main principal is to use Jquery to hide part of the table when a specific cell or row is clicked.

Peek at the final product.

There are several really great Jquery html integration tutorials on the web. In fact this is a really great one. The previously linked page details how to setup Jquery to easily create zebra rows, row hover effect and row filtering. I will be showing you something a little different but equally easy to setup.

I will be setting up a table so that when you click on the head row the body will collapse or hide. This sounds pretty easy if you have a little Jquery knowledge but I am going to show you a few things that make the effect easy to reproduce when you do not know how many tables you will end up with. The main problem that I was having with the Lotus web application was that the tables was being created dynamically. Some times there might be 3 tables and sometimes there might be 10. Also I had nested tables which complicates things a little. I will explain more as we get into it. So lets start.

First we are going to need a table. I am going to assume you know how to create a table in html. There are a few important parts. The table needs a head section and a body section.

SingleTable

<table class="StateTable" rules="all" cellpadding="0" cellspacing="0">
   <thead>     <!--You need to have a table head section-->
      <tr class="statetablerow">
         <th>Missouri</th>     <!--Use "th" tags for your table heading cells-->
         <th>Type</th>
         <th>Users</th>
      </tr>
   </thead>     <!--Close the table head section-->
   <tbody>     <!--Open the table body section-->
      <tr>
         <td></td>     <!--Use normal "td" tags for the body cells-->
         <td>Admin</td>
         <td>User Name #1</td>
      </tr>
      <tr>
         <td></td>
         <td>Reader</td>
         <td>User Name #2</td>
      </tr>
      <tr>
         <td></td>
         <td>Reader</td>
         <td>User Name #3</td>
      </tr>
   </tbody>
</table>

We are going to nest a new table inside the last row of the first table. We need to create a new row and a single cell that spans all the columns of the table. With a nested table the code should look like this.

NestedTable

<table class="StateTable" rules="all" cellpadding="0" cellspacing="0">
   <thead>
      <tr class="statetablerow">
         <th>Missouri</th>
         <th>Type</th>
         <th>Users</th>
      </tr>
   </thead>
   <tbody>
      <tr>
         <td></td>
         <td>Admin</td>
         <td>User Name #1</td>
      </tr>
      <tr>
         <td></td>
         <td>Reader</td>
         <td>User Name #2</td>
      </tr>
      <tr>
         <td></td>
         <td>Reader</td>
         <td>User Name #3</td>
      </tr>
      <tr>     
         <td colspan="3" >   <!--Added row for the nested table-->
            <table class="CityTable" rules="all" cellpadding="0" cellspacing="0">     <!--Start of the nested table-->
               <thead>
                  <tr>
                     <th>St. Louis</th>
                     <th>Type</th>
                     <th>Users</th>
                  </tr>
               </thead>
               <tbody>
                  <tr>
                     <td></td>
                     <td>Admin</td>
                     <td>User Name #1</td>
                  </tr>
                  <tr>
                     <td></td>
                     <td>Reader</td>
                     <td>User Name #2</td>
                  </tr>
                  <tr>
                     <td></td>
                     <td>Reader</td>
                     <td>User Name #3</td>
                 </tr>
              </tbody>
           </table>
        </td>
     </tr>
   </tbody>
</table>

Ok now for the fun stuff. With the correct ground work setup we can now implement our Jquery JavaScript code. The first thing to do is link the Jquery library. You can do this by linking directly from Googles code server, from Jquery or download and host your own copy. I chose to link from Google. This code goes in the head section of your page.

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>

You may have noticed that both of my tables have classes applied to them. This is so we can determine if the user clicked on the outer or inner table. If you have multiple inner tables they would have the same class. We now have to create the javascript that Jquery will use. I will start with the inner city table.

$('table.CityTable th') .click(
	function() {
		$(this) .parents('table.CityTable') .children('tbody') .toggle();
	}
)

That is it, not much to it. This needs to go into a Document.ready function so it will be loaded when the page is finished loaded. See Jquery documentation if you do not know what I am talking about. To help you understand I will go over this line by line.

$(‘table.CityTable th’) .click(
This line starts the Jquery function. It tells Jquery to find the css element “table.CityTable th” or a header cell inside a table that has the class of CityTable. Then because elements in one line are executed right after each other the “.click” tells Jquery to add a click event to the previous css element.
function() {
This line opens the function that will happen when the click event is triggered.
$(this) .parents(‘table.CityTable’) .children(‘tbody’) .toggle();
This is where the magic happens. It is a long one so I will try and explain each part. When the click event goes off it will trigger this line. Start with a Jquery function as before but instead of putting the css element we want to use we put the text “this“. “This” refers to the element being used in the triggering function, which is “table.CityTable th“.
Then we apply the selector “.parents()” which tells Jquery to look for the previous element that is “table.CityTable“. Effectively we are now selecting the css element “table.CityTable” where the click happened. So if you have more than one table with this element you will only select the table were the user clicked. However our main objective is to had the body of the table when the user clicks on the header.
With the table now selected we need to continue and select just the body. This happens with the “.children()” selector. It tells Jquery to look for the next “tbody” tag within the previous element. Now we have effectively selected the css element “table.CityTable tbody” within the table where the click happened.
Finally with the right element selected we can hide it. Jquery has a simple function for this called “.toggle()“. If no properties are passed to this function it just hides the selected element by applying a style of display:none.
} )
This is what’s left. It closes the inner function and the click event.

Now the outer table has very similar code however because you select elements via CSS it can be tricky to pick the correct selector. If you use “table.StateTable th” you end up selecting not only the row you intended but also the other “th” cells in the nested table. That is because the before mentioned selector picks any and all “th” tags within the “StateTable” class. We can get around this by adding a class to the header row of the outer tables header row. This will keep our selector with the row that has the “.statetablerow” class.

$('table.StateTable tr.statetablerow th') .click(
	function() {
		$(this) .parents('table.StateTable') .children('tbody') .toggle();
	}
)

This is extremely similar to the inner table code. The best part is because we used the parents and children selectors we avoid having to create code for each table we want to have the effect. Also it allows you to use the same code over multiple pages or for any number of tables on the same page. Add some css to make things look a little nicer and you are all set.

Here is an example of the effect. I have listed the css and javascript in the document. Use firebug or your favorite code inspector.

Accordion Table Example

  • http://www.meconzee.com zeechina

    It is very nice code, I want on page load
    table should be collapse.

    Please help where I have to change for this.

  • http://www.inviongps.net/ Loura Linssen

    27. Fantastic function, your blog is extremely informative and no bluff phrases. I am looking forward to your new post article and i am glad if you maintain me posted through my email.

  • gruppler

    colspan=”3″ should be applied to the TD. Doesn’t make sense to apply it to a TR.

  • Jonathan

    You are very right. The example has the correct html in it. I have updated this post. Thank you.

  • http://en.wikipedia.org/wiki/Harold_Perrineau purple black

    Thank you for a great post.

  • RajRam

    You have excellent skills to explain things….I like your websit…
    Good Work

  • Anonymous

    Awsome post!! For people wanting the table to be collapsed on page load just add:

    $(‘table.CityTable th’).parents(‘table.CityTable’).children(‘tbody’).toggle();

    $(‘table.StateTable tr.statetablerow th’).parents(‘table.StateTable’).children(‘tbody’).toggle();

    before the (document).ready function closes with });
    look source code on example

  • Abhinav Siddharth

     Hi, I was wondering if its possible to have it within a table. I have
    gone through your accordion example for table, which solves half of my
    problem but now I need that toggle things should happen only when you
    click on first column of the table and not the entire header. Any
    possible solutions you have?

    Much appreciate your response. Thanks!

    P.S I’ve asked the same question on your sliding menu tutorial as well :)

  • Abhinav Siddharth

    Hi, me again. My jquery works fine but i am stuck with small issue.
    I need to change the image in first column when I click on it. Very similar to what you have put on your menu example but that example is very complex for me. I have been able to achieve everything with this jQuery except changing the image. Could you please help me out????? Thanks much!

  • Stephen Laring

     how to hide the nested table on page load?

  • Anonymous

    Hi, I was wondering how to get each open panel to close whenever another panel is clicked?   Right now you have to click to close an open panel and I would prefer to utilize toggle to open a clicked panel and close any open panel.

    This is a great tutorial by the way.  Awesome job.  Thanks!