A Scrollable Table With a Fixed Header

NOTE: the concepts presented in this article are now considered obsolete possibly because better alternatives are available.

Consider this solution as obsolete as there are better alternatives available. Search the comments to this article for a few external links to better implementations.

If you need to present a lot of table based data, but you don't want to spoil your page layout with a very long table, you can use the following trick to create a scrollable table with a fixed header.

To embed a scrollable table with a fixed header in your page, you don't have to use an <iframe> tag; all you need is a simple <div> with some CSS applied, like this:

<table style="width: 300px" cellpadding="0" cellspacing="0">
  <td>Column 1</td>
  <td>Column 2</td>

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

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 <div> 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 <div>.

The width of the outer <div> 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.

Below you can see the code in action. As you can see, the table header stays put on the page, while you can scroll up and down in the table:

Column 1 Column 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2
Value 1 Value 2


If you want the scrollbars to appear regardless of the size of the inner table, set the overflow to scroll instead of auto.

Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .

Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.

Feedback by Other Visitors of Imar.Spaanjaars.Com

On Thursday, March 24, 2005 9:20:34 AM D said:
Try setting the header title of the first header to 'A longer title'and your method breaks down...
On Thursday, March 24, 2005 9:32:57 AM Imar Spaanjaars said:
Yes, it does, obviously. Because this new header and the header for column 2 together no longer fit in the 300px width.

You'll need to adjust the outer table and div to support wider columns.....

On Thursday, March 24, 2005 11:20:47 AM Imar Spaanjaars said:
Alternatively, set an explicit width on the first cells of each table. E.g.:

<td width="50%">A longer title</td>
<td width="50%">Column 2</td>


<td width="50%">Value 1</td>
<td width="50%">Value 2</td>

On Wednesday, April 20, 2005 7:40:43 PM JulianaRP said:
What about on IE 5.2??
When I do this kind of table with a scrollbar, the browser has a scrollbar to the actuall lenght of the content regardless of what the overflow value is.
Look at http://www.julianarp.com/2/discography.html for an example.
On Wednesday, April 20, 2005 10:08:33 PM Imar Spaanjaars said:
Hi there,

I don't have a Mac right here, so I can't test this. However, IE 5.2 is known for its very lousy implementation of (X)HTML and Css standards, so I wouldn't be surprised if this wouldn't render correctly at all without some browser hacks to detect this browser.
Did you try it in IE 5.5 on a Mac?

On Wednesday, April 20, 2005 10:51:01 PM juliana said:
The scrollbar appears to work fine on most everything except IE 5.2 as far as I can tell.
But, after much searching I found that the solution appears to be...

In the exterior css -

Body {
overflow: hidden;


Who knew! Is that a hack? What's a hack?
On Thursday, April 21, 2005 9:06:26 PM Imar Spaanjaars said:
No, I wouldn't consider that a hack.

I consider stuff like this a hack: http://tantek.com/CSS/Examples/boxmodelhack.html (a very good one at that) or some of the stuff mention on this site: http://www.positioniseverything.net/

On Thursday, May 05, 2005 9:23:33 PM Luis said:
Your example only works because all header strings have the same length and all row strings have the same length.
On Tuesday, April 11, 2006 2:14:06 PM Patrick Kraaij said:
Very simple but effective CSS snippit. I use it for my new project at the moment to display all the pages. And that list is getting longer and longer, I didn't know a proper solution. I don't want that the page scrolls so I thought I might have to use the iframe. But luckly after I found this article I haven't use the iframe. A perfect solution!
On Friday, June 09, 2006 6:19:03 AM Valar said:
I have more complex problem than this.

My column values vary in sizes dynamically so the header and columns are always mis aligned. To avoid this I included my text within the header and ser the header style to be fixed. as

                                             [HeaderStyle CssClass="ms-formlabel DataGridFixedHeader"][/HeaderStyle]

and my css:

COLOR: white;
POSITION: relative;  
TOP: expression(this.parentNode.parentNode.
    border-color:#999999; }

This works fine with a fixed header and scrollable table.

the problem is My gridview control is placed within a Div. Also as you know the grid view control is rendered as div. There is some kind of mis alignment happening whent he page size is changed. I hope is you have worked on complex solutions you might have come across similar problems.

Is there a way to prevent the Div tags from misaligning?

Any help will be appriciated.

On Saturday, June 10, 2006 2:46:36 PM Imar Spaanjaars said:
Hi Valar,

Unfortunately, I don't understand what the problem is. Can you post your code and describe the problem in more detail at http://p2p.wrox.com? If you send me the link, I'll take a look.

On Monday, June 26, 2006 11:42:27 PM bdc604 said:
A great control, but if the list was extensive how do you maintain the scroll position after postback?
On Saturday, July 01, 2006 6:00:54 PM Imar Spaanjaars said:
Hi there,

If you're using ASP.NET 2, you can use the MaintainScrollPositionOnPostBack property of the page class, desribed here:



On Friday, July 07, 2006 8:26:22 PM Gary Campbell said:
This is a nice simple solution.  My concern is that it violates one of the basic concepts of the web: don't convey structure
with presentation.  The table containing the column headings is a separate entity, the only reason it conveys the
relationship that it contains headers for the following table is because it happens to be positioned over the other table.  
That sounds like a knit-picky theoretical idealistic rant until one of those theoretically possible alternative  nonvisual
display browsers, such as, for example, speech, encounters your web page.  When that happens all this idealistic stuff
becomes very practical, especially if it affects your job!  I am a blind computer user.  My screen reading software (JAWS)
needs to know that relationship to provide the meaning expressed by the visual position of the headers, but it cannot
determine that the cells in the other table are the headings for the scrolling table, its best guess is the values in the
first row of the scrolling table.  The reason I found this page is because I was looking for a solution for a client for whom
I did accessibility testing of a page with such an implementation.  Unfortunately, using the HEADERS attribute on the data
table cells and pointing it to the appropriate cell in the other table doesn't work either, which could be argued is a
problem with the screen reader.  For the scrolling body with fixed headers effect to also provide accessible column headers
the headers must be in the same table.  There is such an implementation at http://www.imaputz.com/cssStuff/bigFourVersion.html, at least it works right in JAWS.  There is other stuff going on in this
example-- I would be interested in the minimum of what is done there to achieve the scrolling table body with fixed headers

BTW:  I'm going to have to have some one read me the characters in the picture.  When they procecute spammers could they also
procecute them for obstructing accessibility :-)?

On Friday, July 14, 2006 6:36:57 PM Imar Spaanjaars said:
Hi Gary,

I sent you a reponse on your private e-mail address.


On Tuesday, May 15, 2007 5:50:57 AM sss said:
I am calling a 2nd jsp page from 1st jsp page. now in 2nd jsp, i have a table.I need the following functionality...
The header of the table shoud be fixed when I scroll vertically but flaxible when i use horizontal scrollbar....

I treied to use div tag.......... But now succeded

On Sunday, August 19, 2007 9:54:55 AM Sandeep Sangole said:
Above code  that you gave works fine , but in my case table data is coming from database which is dynamic.If the data size increases the header wont increase.
Please tell me how to avoid this problem?
On Monday, September 10, 2007 2:49:45 PM Pratul Shukla said:
I am also facing the same problem as told by sandeep sangole. I am also getting table data from database which is dynamic where no. of columns may exceed to about 30-40 columns while around 150 rows.
Please help how fix the header as it becomes very difficult after coming to 50th row and then again scrolling back to 1st row to see actually which column i am looking at.......!!!!!
On Monday, September 10, 2007 6:32:51 PM Imar Spaanjaars said:
Hi Pratul,

My solution won't work with column or content widths that you can't predict. You need to look at other solutions involving floating divs and/or JavaScript.

Personally, I don't think anyone wants to read a 40 x 50 sized Grid anyway, but that's just my opinion. Maybe your application requires it....

On Tuesday, September 11, 2007 12:39:23 PM Pratul Shukla said:
Thanks Imar for your quick reply...

Actually we are reading excel sheet and displaying it in grid format and there we are expecting more no. of columns and row's. currently i am using div but i was not able to fix the header . If you have got any reference do tell it to me........
On Friday, October 12, 2007 6:14:06 AM subrahmanyam said:
In the scrollable table i need to add maximum 10 rows.then how can i proceed
On Friday, October 12, 2007 6:26:09 AM Imar Spaanjaars said:

What's the point of having a scrollable header with only ten records??

I think you want to look into "Paging"....

On Monday, November 19, 2007 3:03:44 PM Santhosh Kumar said:
This was a gr8 one.. But I have one query.. It works Fine with ASP Technology right?
On Monday, November 19, 2007 7:45:08 PM Imar Spaanjaars said:
Hi Santhosh,

Sure, why not? ASP just generates HTML after all.... If it works for you in HTML, you can generate the same code with ASP.

On Friday, January 25, 2008 8:03:48 PM Shand Glenn said:
I am looking for something that would fix both left header and top header.  Any suggestions?
On Saturday, January 26, 2008 10:41:10 AM Imar Spaanjaars said:
Hi Shand,

You could create two floating divs and position them next two each other using the CSS float property. Then you could give the right div fixed dimensions and a scrollbar.

On Wednesday, January 30, 2008 6:03:11 AM Surekha Matte said:
Hi Valar,

The below code:
COLOR: white;
POSITION: relative;  
TOP: expression(this.parentNode.parentNode.
    border-color:#999999; }

This works fine with a fixed header and scrollable table.

Its working fine in IE but not in mozilla.. In mozilla the header grid also scrolling :( can you please what i have to do changes for mozilla....
On Wednesday, May 21, 2008 5:58:14 AM Anu said:

I tried out this.It is working fine; but giving alignment problem. My table have around 14500 rows which are being fetched from database. Is it the right method to use for such a table or you would like to suggest something else.

On Thursday, September 11, 2008 12:05:05 PM Claude Michaud said:
I created a small solution that resizes the header columns to the body columns and allows to expand the table to display all its rows if needed to print.

In the source that follows, all the tags opening and closing are replaced by [ and ]

[!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"]
[html xmlns="http://www.w3.org/1999/xhtml"]
  [meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" /]
  [title]Table with scroll[/title]
  [style type="text/css"]
    body, table  {font-family: verdana, arial, sans-serif; font-size: 10px;}
    #tableheader {background-color: lavender; border-top: solid 1px #808080; border-right: solid 1px #808080;}
    #tablebody   {border-right: solid 1px #808080;}
    td           {color:blue; border-bottom: solid 1px #808080; border-left: solid 1px #808080;}

    // This routine, called by the small button expands or
    // shrink the div containing the "body" rows, by switching
    // the overflow property. The timeout to call the adjusting
    // routine is just to give time to the browser to interpret
    // all events.
    function expand_scroll() {
      var es = document.getElementById('divbody').style;
      if (es.overflow=='auto') es.overflow='';
      else es.overflow='auto';
      var t=setTimeout("adjust()",20);
    // This routines first adjusts the body table width to its division
    // width. Then it retrieves the first row TableCells objects in both
    // tables and adjust the width of the "header" columns at the size
    // of the "body" columns, taking out the pixels for the borders as we
    // work with width and clientWidth.
    function adjust() {
      var offset;
      if(navigator.appName=='Microsoft Internet Explorer') offset=2;
      else offset=2;
      var d=document.getElementById('divbody').clientWidth;
      document.getElementById('tablebody').style.width= (parseInt(d)-2)+'px';
      var y=document.getElementById('tableheader').rows[0].cells;
      var x=document.getElementById('tablebody').rows[0].cells;
      for (i=0;i[document.getElementById('tableheader').rows[0].cells.length;i++) {
        y[i].width = (parseInt(x[i].clientWidth)-offset)+'px';

[body onload="adjust();" onresize="adjust();"]
On Friday, October 31, 2008 1:39:23 PM zaghdoudi said:
it's a good solution for static table only  the problem is to use the solution with dynamic table(ajax table) then we need to adjust the header dimension to the body dimension
On Friday, December 05, 2008 10:52:34 AM shahib said:

Check this out.. http://www.s7u.blogspot.com.. This has fixed header, fixed footer, fixed right and left column..

On Saturday, February 06, 2010 2:03:22 PM Jaimon Mathew said:
Hi Guys, an easy to implement table scroller is explained here http://jaimonmathew.wordpress.com/2010/02/02/scroller/
It has support for ie6/7/8, firefox and chrome, and works on fixed and variable width tables.

On Monday, February 08, 2010 7:27:24 PM Chris Levy said:
Your scrolling table works great on my very long list of vinyl records. Its on my website at www.woodleynet.co.uk/index3.htm. See "My Vinyl Records" link on left. I still cant get the search form to work in Mazilla Firefox tho'
On Monday, February 08, 2010 7:31:51 PM Imar Spaanjaars said:
Hi Chris,

You mean searching on my web site? Yes, I know; it's broken and I haven't head the time to fix it yet ;-)

On Monday, February 08, 2010 8:52:00 PM Chris Levy said:
No I meant the one on my scrolling table page. Nothin to do with your table tho. I think the code was made for the search form before Mozilla was available
Cheers Chris
On Wednesday, March 03, 2010 8:03:20 PM nithin surendran said:
we are really thankful for this website.. we was in search of the content given in the table for few days....

really thankx...!!! thankx a lot..!!!!
On Thursday, April 15, 2010 8:56:49 PM Sandeep said:
Try this, it works perfectly. Tested in IE7, 8.
        div.encsheet {
        div.encsheet thead tr td{
         top: expression(offsetParent.scrollTop==0 ? 0+""+(offsetParent.scrollTop=-1)+""+(offsetParent.scrollTop=1) : offsetParent.scrollTop-2);
            left: expression(offsetParent.scrollTop==0 ? 0+""+(offsetParent.scrollTop=-1)+""+(offsetParent.scrollTop=1) : -1);
On Sunday, May 16, 2010 3:39:59 AM Anne said:
This article is EXCELLENT!! I have visited many sites trying to figure out how to build a scrollable table with fixed header. Your site is the only one that showed me how to do it clearly and concisely. I am now following your you on Twitter. You should be sending out information about your articles regularly on Twitter. They are VERY helpful. Once again thanks.
On Sunday, May 16, 2010 6:34:09 AM Imar Spaanjaars said:
Hi Anne,

>> Your site is the only one that showed me how to do it clearly and concisely.
Please read the comments below this article, and you'll find (better) alternatives.

>> You should be sending out information about your articles regularly on Twitter.
I already do that so stay tuned. Most of what I write is related to ASP.NET and not to client side development though.


On Tuesday, July 27, 2010 8:24:18 AM Sarah Bruce said:
I, like Gary in 2006, am looking at way of doing this that is also accessible to all our customers. Would you be able to send your reply to Gary also to me so we can research a solution that satisfies all our customers.

On Tuesday, July 27, 2010 11:41:37 AM Imar Spaanjaars said:
Hi Sarah,

I just forwarded you that message.


On Monday, August 23, 2010 12:00:54 PM Shahib said:
Hi buddy,

I have implemented complete scrollable table with fixed header and footer using CSS and Javascript. This works fine in IE, Firefox and most importantly Google Chrome.

This may be helpful ;-)

On Monday, October 04, 2010 3:16:07 PM Chris said:
This one works the best for me so far:
On Thursday, October 28, 2010 9:19:24 AM Ankit Sharma said:
i m using div inside the div in first div two div.one div is image and another div is title but when i am small browser then title is going inside the image.i am not fixing the position of title.so please tell me solution....
On Monday, December 06, 2010 9:51:50 AM benjamin said:
look at this blog : http://tablefixedheader.com

On Sunday, January 16, 2011 5:49:55 PM Suresh said:

I am facing problem with fixed header but not in .net but in jsp. In my jsp page, i have placed a table contains all the data including header comes from database in a div layer with overflow attribute as scroll. but not getting any idea how to fix the header values in the table. Please help me to fix the header in my jsp page. Please send mail to suresh.vv47@gmail.com
On Sunday, January 16, 2011 6:07:28 PM Imar Spaanjaars said:
Hi there,

This is a client solution so the server technology should be irrelevant. Additionally, this article is considered obsolete, as explained at the top of the article.


On Thursday, April 14, 2011 10:26:37 PM Shyam said:
This way of coding will not have proper alignment when u have table borders. The data table will be aligned differently when compared to table header.
On Friday, April 15, 2011 12:57:31 AM Imar Spaanjaars said:
Hi Shyam,

As hinted at the top of this article, the solution presented here should be considered obsolete. Check the comments for better alternatives.


On Thursday, May 05, 2011 11:06:25 AM Emma Garland said:
Thanks for this article, the simple and elegant solution has worked well for me without any hacks needed, and I wish I'd found your article first! I've extended it to use a fixed footer the exact same way and it works great.
On Thursday, May 19, 2011 6:28:01 AM praveen said:
Your code is simple and useful but i was getting some problem in gridview..

Am doing gridview fixed headertext,when i put the headertext it working fine but when am using some javascript in textbox of the same grid then the headertext of gridview is moving up from the panel..if i removed javascript function its working fine but javascript is must and should for my requirement.

Requirement is: i need header and footer for gridview including sorting, javascript functions and footertext.

the javascript function is to take value from all textboxes so when am pressing tab button its getting error...
On Thursday, May 19, 2011 12:56:03 PM Imar Spaanjaars said:
Hi there,

Take another look at the start of this article to see these ideas are obsolete and for pointers to other solutions.


On Friday, May 27, 2011 10:17:25 AM Ekta said:
I did tried lots of script and JQuery library, but if it's a big table with lots of rows few of this scripts make it slow, few script does not works in some browser. At last I found the best way to create the scrollable table with fixed row or column. I am using it in my huge ERP application, it is really fast and works great on Mozilla Firefox, IE, Opera and Google chrome. To see the detail please visit to
On Wednesday, September 07, 2011 11:36:50 PM Dhanu said:
Thanks for this article, the simple and elegant solution has worked well for me .
On Tuesday, November 15, 2011 11:56:47 PM Vivek Gupta said:
I found a best solution for horizontal and vertical scrolling table with static header (fixed header ) and i tested it in all browser even ie 7,8,9 with compatibility mode and normal mode

**Check It Now :-**

On Wednesday, April 25, 2012 1:32:58 PM www.csharpaspnetarticles.com said:
On Thursday, June 06, 2013 7:53:11 PM David said:
Found adding an extra TD in both the table header and table body really helps if the columns are of different width.  THANKS SO MUCH!!!!
On Sunday, July 21, 2013 2:17:42 PM Noha said:

Thanks for the demo.

Plz, how to make the footer also fixed ??????
On Monday, September 16, 2013 6:22:09 AM Ravi said:
Above code works only when 2 tables data contains fixed width.
If data at below table's row is more then headers will be out of sync.

Not use for code which is dynamically created / fetched

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.