How to scroll table's "tbody" independent of "thead"?

JavascriptHtmlCss

Javascript Problem Overview


As specified in the W3 specification for Tables:

> Table rows may be grouped into a table head, table foot, and one or > more table body sections, using the THEAD, TFOOT and TBODY elements, > respectively. This division enables user agents to support scrolling > of table bodies independently of the table head and foot.

I created the following example, but it doesn't work.

HTML:

<table>
    <thead>
        <tr>
            <td>Problem</td>
            <td>Solution</td>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>

JS:

$(function() {
    for (var i = 0; i < 20; i++) {
        var a = Math.floor(10 * Math.random());
        var b = Math.floor(10 * Math.random());
        var row = $("<tr>").append($("<td>").html(a + " + " + b + " ="))
                           .append($("<td>").html(a + b));
        $("tbody").append(row);
    }
});

CSS:

table {
    background-color: #aaa;
}
tbody {
    background-color: #ddd;
    height: 100px;
    overflow: auto;
}
td {
    padding: 3px 10px;
}

Javascript Solutions


Solution 1 - Javascript

The missing part is:

thead, tbody {
    display: block;
}

Demo

Solution 2 - Javascript

I saw this post about a month ago when I was having similar problems. I needed y-axis scrolling for a table inside of a ui dialog (yes, you heard me right). I was lucky, in that a working solution presented itself fairly quickly. However, it wasn't long before the solution took on a life of its own, but more on that later.

The problem with just setting the top level elements (thead, tfoot, and tbody) to display block, is that browser synchronization of the column sizes between the various components is quickly lost and everything packs to the smallest permissible size. Setting the widths of the columns seems like the best course of action, but without setting the widths of all the internal table components to match the total of these columns, even with a fixed table layout, there is a slight divergence between the headers and body when a scroll bar is present.

The solution for me was to set all the widths, check if a scroll bar was present, and then take the scaled widths the browser had actually decided on, and copy those to the header and footer adjusting the last column width for the size of the scroll bar. Doing this provides some fluidity to the column widths. If changes to the table's width occur, most major browsers will auto-scale the tbody column widths accordingly. All that's left is to set the header and footer column widths from their respective tbody sizes.

$table.find("> thead,> tfoot").find("> tr:first-child")
    .each(function(i,e) {
        $(e).children().each(function(i,e) {
            if (i != column_scaled_widths.length - 1) {
                $(e).width(column_scaled_widths[i] - ($(e).outerWidth() - $(e).width()));
            } else {
                $(e).width(column_scaled_widths[i] - ($(e).outerWidth() - $(e).width()) + $.position.scrollbarWidth());
            }
        });
    });

This fiddle illustrates these notions: http://jsfiddle.net/borgboyone/gbkbhngq/.

Note that a table wrapper or additional tables are not needed for y-axis scrolling alone. (X-axis scrolling does require a wrapping table.) Synchronization between the column sizes for the body and header will still be lost if the minimum pack size for either the header or body columns is encountered. A mechanism for minimum widths should be provided if resizing is an option or small table widths are expected.

The ultimate culmination from this starting point is fully realized here: http://borgboyone.github.io/jquery-ui-table/

A.

Solution 3 - Javascript

try this.

table 
{
    background-color: #aaa;
}

tbody 
{
    background-color: #ddd;
    height: 100px;
    overflow-y: scroll;
    position: absolute;
}

td 
{
    padding: 3px 10px;
    color: green;
    width: 100px;
}

Solution 4 - Javascript

thead {
  position: fixed;
  height: 10px; /* This is whatever height you want */
}
  tbody {
  position: fixed;
  margin-top: 10px; /* This has to match the height of thead */
  height: 300px; /* This is whatever height you want */
}

Solution 5 - Javascript

mandatory parts:

tbody {
    overflow-y: scroll;  (could be: 'overflow: scroll' for the two axes)
    display: block;
    with: xxx (a number or 100%)
}

thead {
    display: inline-block;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMisha MoroshkoView Question on Stackoverflow
Solution 1 - JavascriptbookcaseyView Answer on Stackoverflow
Solution 2 - JavascriptBorgboyView Answer on Stackoverflow
Solution 3 - JavascriptBhimbimView Answer on Stackoverflow
Solution 4 - JavascriptJohn K. ChowView Answer on Stackoverflow
Solution 5 - JavascriptfreignatView Answer on Stackoverflow