41

Is it possible to make a table row expand and collapse? Can anyone refer me to a script or an example?

I prefer jQuery if possible. I have a drawing concept I would like to achieve:

alt text

M--
  • 25,431
  • 8
  • 61
  • 93
Erik
  • 5,701
  • 27
  • 70
  • 119

6 Answers6

56

Yes, a table row can slide up and down, but it's ugly since it changes the shape of the table and makes everything jump. Instead, put an element in each td, something that makes sense like a p or h2 etc.

As for implementing a table slide toggle...

It's probably simplest to put the click handler on the entire table, .stopPropagation() and check what was clicked.

If a td in a row with a colspan is clicked, close the p in it. If it's not a td in a row with a colspan, then close then toggle the following row's p.

It is essential to wrap all your written content in an element inside the tds, since you never want to slideUp a td or tr or table shape will change!

Something like:

$(function() {
  
      // Initially hide toggleable content
    $("td[colspan=3]").find("p").hide();

      // Click handler on entire table
    $("table").click(function(event) {

          // No bubbling up
        event.stopPropagation();

        var $target = $(event.target);

          // Open and close the appropriate thing
        if ( $target.closest("td").attr("colspan") > 1 ) {
            $target.slideUp();
        } else {
            $target.closest("tr").next().find("p").slideToggle();
        }                    
    });
});​

Try it out with this jsFiddle example.

... and try out this jsFiddle showing implementation of a + - - toggle.

The HTML just has to have alternating rows of several tds and then a row with a td of a colspan greater than 1. You can obviously adjust the specifics quite easily.

The HTML would look something like:

<table>
    <tr><td><p>Name</p></td><td><p>Age</p></td><td><p>Info</p></td></tr>
    <tr><td colspan="3"><p>Blah blah blah blah blah blah blah.</p>
    </td></tr>

    <tr><td><p>Name</p></td><td><p>Age</p></td><td><p>Info</p></td></tr>
    <tr><td colspan="3"><p>Blah blah blah blah blah blah blah.</p>
    </td></tr>
    
    <tr><td><p>Name</p></td><td><p>Age</p></td><td><p>Info</p></td></tr>
    <tr><td colspan="3"><p>Blah blah blah blah blah blah blah.</p>
    </td></tr>    
</table>​
Hiebs915
  • 666
  • 1
  • 7
  • 22
Peter Ajtai
  • 56,972
  • 13
  • 121
  • 140
  • @Peter-Ajtai Would you be able to help me with this issue Peter? http://stackoverflow.com/questions/23916317/table-row-sliding-bug-mvc-5 – Austin May 28 '14 at 16:04
  • @peter i have a similar problem like this but my HTML table is totally dynamic if you get some time please help https://stackoverflow.com/questions/55919420/how-to-make-html-table-expand-on-click?noredirect=1#comment98648939_55919420 – manish thakur May 06 '19 at 11:16
  • 1
    Hello, I tried this solution and its working perfectly at the moment. However if I click on the bottom most portion of the expanded row (port expand) it will make my expanded row vanish entirely with no way to re-expand without refreshing the page. – FamousAv8er Sep 03 '19 at 14:47
  • For your fiddle it seems to behave the same if you click towards the top of the expanded row. – FamousAv8er Sep 03 '19 at 14:55
  • 1
    Below is a link to my question. The answer provided fixes this solutions bug where you can no longer see an expandable row. https://stackoverflow.com/questions/57776725/expanding-table-row-issue-from-previous-solution – FamousAv8er Sep 03 '19 at 21:02
  • When trying to select text for copy, it will also expand. Small issue, but can be annoying. – ViliusL Jun 17 '21 at 11:57
  • 1
    This isn't valid HTML and is a terrible experience for screen reader users. Tables need to have headers, so in this case, when you add a row with colspan="3", the expandable/collapsible row would not work with the headers – Tim Winfred Jan 04 '22 at 17:03
13

You could do it like this:

HTML

<table>
    <tr>
        <td>Cell 1</td>
        <td>Cell 2</td>
        <td>Cell 3</td>
        <td>Cell 4</td>
        <td><a href="#" id="show_1">Show Extra</a></td>
    </tr>
    <tr>
        <td colspan="5">
            <div id="extra_1" style="display: none;">
                <br>hidden row
                <br>hidden row
                <br>hidden row
            </div>
        </td>
    </tr>
</table>

jQuery

$("a[id^=show_]").click(function(event) {
    $("#extra_" + $(this).attr('id').substr(5)).slideToggle("slow");
    event.preventDefault();
});

See a demo on JSFiddle

M--
  • 25,431
  • 8
  • 61
  • 93
Valentin Flachsel
  • 10,795
  • 10
  • 44
  • 67
3

It depends on your mark-up, but it can certainly be made to work, I used the following:

jQuery

$(document).ready(
  function() {
  $('td p').slideUp();
    $('td h2').click(
      function(){
       $(this).siblings('p').slideToggle();
      }
      );
  }
  );

html

  <table>
  <thead>
    <tr>
      <th>Actor</th>
      <th>Which Doctor</th>
      <th>Significant companion</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><h2>William Hartnell</h2></td>
      <td><h2>First</h2><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p></td>
      <td><h2>Susan Foreman</h2><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p></td>
    </tr>
    <tr>
      <td><h2>Patrick Troughton</h2></td>
      <td><h2>Second</h2><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p></td>
      <td><h2>Jamie MacCrimmon</h2><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p></td>
    </tr>
    <tr>
      <td><h2>Jon Pertwee</h2></td>
      <td><h2>Third</h2><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</p></td>
      <td><h2>Jo Grant</h2><p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p></td>
    </tr>
  </tbody>
</table>

The way I approached it is to collapse specific elements within the cells of the row, so that, in my case, the row would slideUp() as the paragraphs were hidden, and still leave an element, h2 to click on in order to re-show the content. If the row collapsed entirely there'd be no easily obvious way to bring it back.

Demo at JS Bin


As @Peter Ajtai noted, in the comments, the above approach focuses on only one cell (though deliberately). To expand all the child p elements this would work:

$(document).ready(
  function() {
  $('td p').slideUp();
    $('td h2').click(
      function(){
       $(this).closest('tr').find('p').slideToggle();
      }
      );
  }
  );

Demo at JS Bin

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • 1
    Good solution, although @Erik's layout would require that the hidden cell is in a different row altogether since it spans across multiple other cells in the row above. – Valentin Flachsel Oct 09 '10 at 19:24
  • True, unfortunately trying to implement this solution with a sibling table-row causes all sorts of unattractive jumping. Possibly with a carefully-nested list it could be done, though. – David Thomas Oct 09 '10 at 20:42
  • You can use `sibling` or `next` and `.find("p")` so that you never have to collapse a `td` or `tr`, and then you can easily implelemnt a `colspan` solution. - See my solution. – Peter Ajtai Oct 09 '10 at 20:54
  • Your jsBin example doesn't close the row if the opened row is clicked on. ----- Also it's very confusing that when you click on something, the entire row opens up, but only the information associated with the one cell you clicked on is shown (the other info in the same row remains hidden). – Peter Ajtai Oct 09 '10 at 21:05
  • @Peter, possibly; but it was more a quick demonstration of intent, rather than a polished, finished implementation. – David Thomas Oct 09 '10 at 21:25
2

jQuery

$(function() {
    $("td[colspan=3]").find("div").hide();
    $("tr").click(function(event) {
        var $target = $(event.target);
        $target.closest("tr").next().find("div").slideToggle();                
    });
});

HTML

<table>
    <thead>
        <tr>
            <th>one</th><th>two</th><th>three</th>
        </tr>
    </thead>
    <tbody>

        <tr>
            <td><p>data<p></td><td>data</td><td>data</td>
        </tr>
        <tr>
            <td colspan="3">
                <div>
                    <table>
                            <tr>
                                <td>data</td><td>data</td>
                            </tr>
                    </table>
                </div>
            </td>
        </tr>
    </tbody>
</table>

This is much like a previous example above. I found when trying to implement that example that if the table row to be expanded was clicked while it was not expanded it would disappear, and it would no longer be expandable

To fix that I simply removed the ability to click the expandable element for slide up and made it so that you can only toggle using the above table row.

I also made some minor changes to HTML and corresponding jQuery.

NOTE: I would have just made a comment but am not allowed to yet therefore the long post. Just wanted to post this as it took me a bit to figure out what was happening to the disappearing table row.

Credit to Peter Ajtai

M--
  • 25,431
  • 8
  • 61
  • 93
Kyle Andersen
  • 81
  • 1
  • 9
1

To answer your question, no. That would be possible with div though. THe only question is would cause a hazzle if the functionality were done with div rather than tables.

Nigel
  • 1,695
  • 1
  • 13
  • 22
0

Well, I'd say use the DIV instead of table as it would be much easier (but there's nothing wrong with using tables).

My approach would be to use jQuery.ajax and request more data from server and that way, the selected DIV (or TD if you use table) will automatically expand based on requested content.

That way, it saves bandwidth and makes it go faster as you don't load all content at once. It loads only when it's selected.

netrox
  • 5,224
  • 14
  • 46
  • 60
  • That covers expansion. What about collapse? – Peter Ajtai Oct 09 '10 at 22:07
  • just add a function to remove the selected DIV element when clicked on. That will "collapse." You will need to add delegate() function to let jQuery bind functions to new elements. – netrox Oct 09 '10 at 23:29