35

Does anyone know how to make a table with a fixed header row and scrollable body rows? I'm using twitter bootstrap if that matters.

This is an example of what I'm trying to create:

http://www.siteexperts.com/tips/html/ts04/page1.asp

All the examples I've seen break it into two separate tables. Was wondering if anyone has a more elegant solution.

Twitter bootstrap also automatically adjusts the column sizes based on content so that's another reason I'd like to keep it in one table

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Jeff Locke
  • 617
  • 1
  • 6
  • 17
  • 1
    possible duplicate of [HTML table with 100% width, with vertical scroll inside tbody](http://stackoverflow.com/questions/17067294/html-table-with-100-width-with-vertical-scroll-inside-tbody) – yankee Feb 20 '15 at 12:57
  • The link in your question is now dead. – j08691 Nov 11 '15 at 17:39
  • the link is not dead when I click it (the link from Yankee at least that I can see) – Drew Nov 11 '15 at 20:44

4 Answers4

52

Just stack two bootstrap tables; one for columns, the other for content. No plugins, just pure bootstrap (and that ain't no bs, haha!)

  <table id="tableHeader" class="table" style="table-layout:fixed">
        <thead>
            <tr>
                <th>Col1</th>
                ...
            </tr>
        </thead>
  </table>
  <div style="overflow-y:auto;">
    <table id="tableData" class="table table-condensed" style="table-layout:fixed">
        <tbody>
            <tr>
                <td>data</td>
                ...
            </tr>
        </tbody>
    </table>
 </div>

Demo JSFiddle

The content table div needs overflow-y:auto, for vertical scroll bars. Had to use table-layout:fixed, otherwise, columns did not line up. Also, had to put the whole thing inside a bootstrap panel to eliminate space between the tables.

Have not tested with custom column widths, but provided you keep the widths consistent between the tables, it should work.

    // ADD THIS JS FUNCTION TO MATCH UP COL WIDTHS
    $(function () {

        //copy width of header cells to match width of cells with data
        //so they line up properly
        var tdHeader = document.getElementById("tableHeader").rows[0].cells;
        var tdData = document.getElementById("tableData").rows[0].cells;

        for (var i = 0; i < tdData.length; i++)
            tdHeader[i].style.width = tdData[i].offsetWidth + 'px';

    });
raffian
  • 31,267
  • 26
  • 103
  • 174
  • 23
    Nice solution, but the column headers does not line up with the column content. – stian Dec 30 '13 at 16:08
  • 1
    Probably due to the scroll bar, but close enough for my needs! With some tweaking I'm sure someone can fix it, I'm surprised it's so difficult with such a great framework like bootstrap, – raffian Dec 30 '13 at 16:21
  • 1
    This is the least ugly solution I've found that doesn't involve wonky JS, so thanks for that. The misalignment is minimal, but it would be nice to find a full fix. – tirdadc Mar 11 '14 at 20:29
  • That's what I ended up doing because I have knockout bound controls in the header. The various fixed header plugins make a dumb copy of the header, and my knockout controls don't function. Now my problem is that I'd need to have some fixed columns too (the first 3 columns), which also contain knockout controls). – Csaba Toth Jul 17 '14 at 17:24
  • To make the column content line up with the column headers, put the same class for column content as column header. Like `col-sm-3` for `th` and `col-sm-3` for `td` for the corresponding column content – abhisek Aug 09 '14 at 16:35
  • 1
    @abhisek tried [that](http://jsfiddle.net/Mq52k/168/), doesn't seem to make any difference; any ideas why? – raffian Aug 09 '14 at 20:25
  • 1
    @raffian it doesn't make any difference because the table columns are equally divided (almost). But if the table contents are larger than the header, the table is messed up. – abhisek Aug 10 '14 at 03:50
  • You can use table-layout:fixed but then just plug in the col-md-1, etc... It would look like and . – Harbinger Oct 27 '15 at 19:43
  • 3
    So many up votes for this answer which only works like %0.01 of the cases: when it is ok to have equal column width. Just surprised... – Ali Ok Mar 02 '16 at 15:33
  • Does make sense to create two table when in fact i just want one? Doesnt seems to be fair creating a table with just having a header.. Sorry but for me doesn't make sense at all. – ePascoal Aug 19 '16 at 16:08
9

Here is a jQuery plugin that does exactly that: http://fixedheadertable.com/

Usage:

$('selector').fixedHeaderTable({ fixedColumn: 1 });

Set the fixedColumn option if you want any number of columns to be also fixed for horizontal scrolling.

EDIT: This example http://www.datatables.net/examples/basic_init/scroll_y.html is much better in my opinion, although with DataTables you'll need to get a better understanding of how it works in general.

EDIT2: For Bootstrap to work with DataTables you need to follow the instructions here: http://datatables.net/blog/Twitter_Bootstrap_2 (I have tested this and it works)- For Bootstrap 3 there's a discussion here: http://datatables.net/forums/discussion/comment/53462 - (I haven't tested this)

4

Interesting question, I tried doing this by just doing a fixed position row, but this way seems to be a much better one. Source at bottom.

css

thead { display:block; background: green; margin:0px; cell-spacing:0px; left:0px; }
tbody { display:block; overflow:auto; height:100px; }
th { height:50px; width:80px; }
td { height:50px; width:80px; background:blue; margin:0px; cell-spacing:0px;}

html

<table>
    <thead>
        <tr><th>hey</th><th>ho</th></tr>
    </thead>
    <tbody>
        <tr><td>test</td><td>test</td></tr>
        <tr><td>test</td><td>test</td></tr>
        <tr><td>test</td><td>test</td></tr>
</tbody>

http://www.imaputz.com/cssStuff/bigFourVersion.html

Stuart
  • 126
  • 5
0
<table class="table table-striped table-condensed table-hover rsk-tbl vScrollTHead">
            <thead>
            <tr>
                <th>Risk Element</th>
                <th>Description</th>
                <th>Risk Value</th>
                <th>&nbsp;</th>
            </tr>
            </thead>
        </table>
<div class="vScrollTable">
            <table class="table table-striped table-condensed table-hover rsk-tbl vScrollTBody">
                <tbody>
                <tr class="">
                    <td>JEWELLERY</td>
                    <td>Jewellery business</td>

                </tr><tr class="">
                    <td>NGO</td>
                    <td>none-governmental organizations</td>
                    </tr>
                </tbody>
            </table>
        </div>





.vScrollTBody{
  height:15px;
}

.vScrollTHead {
  height:15px;
}

.vScrollTable{
  height:100px;
  overflow-y:scroll;
}

having two tables for head and body worked for me