10

Possible Duplicate:
HTML table with fixed headers?

Looking for a solution to create a table with a scrollable body, and a static/fixed header.

Searching around seems to produce MANY flaky pieces of code, either not working in IE, requiring a huge amount of Javascript and tweaking, or a silly amount of CSS hacks etc.

To be honest, if it's a case of CSS hacks or Javascript, I think I'd prefer to go the Javascript option.

The alternative I guess is to place it all in a div, and just scroll the entire table - but that's a bit naff :D

Community
  • 1
  • 1
Nick
  • 1,233
  • 13
  • 26
  • 37

6 Answers6

9

I've just put together a jQuery plugin that does exactly what you want. Its very small in size and really easy to implement.

All that is required is a table that has a thead and tbody.

You can wrap that table in a DIV with a classname and the table will always resize to fit in that div. so for example if your div scales with the browser window so will the table. The header will be fixed when scrolling. The footer will be fixed (if you enable a footer). You also have the option to clone the header in the footer and have it fixed. Also if you make your browser window too small and all columns can't fit...it will also scroll horizontally (header too).

This plugin allows the browser to size the columns so they aren't fixed width columns.

you just pass the DIV's classname to the plugin like so: $('.myDiv').fixedHeaderTable({footer: true, footerId: 'myFooterId'}); and the plugin will do the rest. FooterID is a element on the page that contains the mark-up for your footer. this is used if you want to have pagination as your footer.

If you have multiple tables on the page it will also work for each table you want to have a fixed header.

check it out here: http://fixedheadertable.mmalek.com/

Keep in mind its still 'beta' so I am adding new features and bug fixes daily.

Supported browsers: IE6, IE7, IE8, FireFox, Safari, and Chrome

Here is a link to my response to another person who had the same question: Frozen table header inside scrollable div

Community
  • 1
  • 1
Mark
  • 5,680
  • 2
  • 25
  • 26
8
<table style="width: 300px" cellpadding="0" cellspacing="0">
<tr>
  <td>Column 1</td>
  <td>Column 2</td>
</tr>
</table>

<div style="overflow: auto;height: 100px; width: 320px;">
  <table style="width: 300px;" cellpadding="0" cellspacing="0">
  <tr>
    <td>Value 1</td>
    <td>Value 2</td>
  </tr>
  <tr>
    <td>Value 1</td>
    <td>Value 2</td>
  </tr>
  <tr>
    <td>Value 1</td>
    <td>Value 2</td>
  </tr>
  <tr>
    <td>Value 1</td>
    <td>Value 2</td>
  </tr>
  <tr>
    <td>Value 1</td>
    <td>Value 2</td>
  </tr>
  <tr>
    <td>Value 1</td>
    <td>Value 2</td>
  </tr>
  </table>
</div>

This creates a fixed column header with the scrollable table below it. The trick is to embed the table you want to scroll in a tag with the overflow attribute set to auto. This will force the browser to display a scrollbar when the contents of the inner table are larger than the height of the surrounding .

The width of the outer must be larger than the width if the inner table to accommodate for the scrollbar. This may be difficult to get exactly right, because some users may have set their scrollbars to be wider or smaller than the default. However, with a difference of around 20 to 30 pixels you'll usually be able to display the scrollbar just fine.

CSS-Tricks also talks about using JavaScript and CSS to help with this as well so you can use highlighting. Here is the link to that article.

Dennis
  • 150
  • 3
  • 9
  • 8
    While this works, it's not great from an accessibility point of view. There are no table headers () and even if there were, they would not be explicitly associated with the relevant columns since the table is broken into two tables. – White Elephant Aug 19 '09 at 16:37
  • This is actually spot on really, if I manually define the width of each column - as pmc said, maybe not ideal from accessibility but all of all the solutions I've seen, this is by *far* my favourite, thank you so much! – Nick Aug 20 '09 at 09:17
  • 1
    If your table is tightly packed at all, this doesn't seem to come out right. – quillbreaker Jan 20 '10 at 16:03
  • Yeah, I was working on a solution similar to this, but I run into an issue where the scrollbar is slightly throwing off the headers. – ScubaSteve Nov 19 '13 at 18:43
3

If you can fix the column widths - it's a lot easier. If you want the browser to figure out the widths, it gets a lot harder. Basically, have the table in div that scrolls (height, overflow:auto) and have that div inside a position:relative div. In the outer div, have another div position:absolute, overflow:hidden, height: whatever the header height is, set this div's innerHTML to the innerHTML of the inner div; Here is a page that demonstrates. There are lots of gotchas, but it's doable...

<html>
<head></head>
<body onload="doit();">
<div id="outer" style="position:relative;">
  <div id="inner" style="height:100px; overflow:auto;">
    <script>
       var html = '<table><tr><th>Heading 1</th><th>Heading 2</th></tr>';
       var width = Math.floor(Math.random() * 100);
       var d = '';
       for(var i = 0; i < width; i++){d += 'a';}
       for(var i = 0; i < 100; i++){
          html += '<tr><td>' + d + '</td><td>some more data</td>';
       }
       html += '</table>';
       document.write(html);
    </script>
  </div>
  <div id="secondWrapper" style="position:absolute; background:#fff; left:0; top:0; height:25px; overflow:hidden;"></div>
</div>

<script>
function doit(){
  var inner = document.getElementById('inner');
  var secondWrapper = document.getElementById('secondWrapper');
  secondWrapper.innerHTML = inner.innerHTML; 
}
</script>
</body>
</html>

Note as you refresh and the data size changes, the header matches up perfectly. That's the real trick.

Steve Brewer
  • 2,062
  • 2
  • 14
  • 15
  • I don't understand how it works at all, so it must be black magic. More seriously, I had to fiddle with the height of my TH tags and the height of secondWrapper to get it to work. It also seems to work a bit better if the table has a maximum width of 98% or so, to keep the table and the scrollbar from bumping into each other. How did you come up with/where did you get this, anyway? It's really clever. – quillbreaker Jan 15 '10 at 21:08
  • Note to others: if you have a table with editable elements, this method copies the table and thus copies the elements. You have been warned. – quillbreaker Jan 15 '10 at 22:30
  • There are a *whole* lot of gotchas. After working with this I think it is not nearly stable enough for use in any production code. It's too late to change my up vote on this answer, though, which is too bad. – quillbreaker Jan 20 '10 at 15:24
2

I believe that the solution is to set an explicit height for the tbody and set the overflow to auto or scroll. Unfortunately, as you've discovered, tables and CSS are a tricky combination, and IE likes to choke on it.

Thom Smith
  • 13,916
  • 6
  • 45
  • 91
2

How about this:

<table style="width: 400px;"> 
<thead><tr> <th> head </th> </tr>
</thead>
<tbody style="height: 100px; overflow-y: auto; overflow-x: hidden;">
<tr> <th> .. </th> </tr>
</tbody>
</table>
goth
  • 21
  • 1
1

There was also a quiz for just this sort of thing on Sitepoint, for those looking for a non-JS solution. However I found that the table footer was necessary for stopping the table headers from collapsing their widths IF the contents of the cells weren't wide enough. I ended up hiding the tfoot in the application I used this on.
It's pure HTML/CSS and works in IE6 plus modern browsers. There are some styling limitations for the header though.