jQuery floating table header plugin

A jQuery plugin that makes the header of a table floating if the original header isn't visible due to scrolling. The plugin will automatically choose the thead tag as the header for a table. If thead isn't found it will search for rows marked with the class 'floating'. The behavior can be changed by the settings forceClass and markingClass.


This plugin is no longer maintained by me and this page will therefore not be updated anymore.

Lazy loading of tables and performance optimations by Jason Axley


1.2.0! Fixed a few bugs and added reinit and recalculate functions to the table.

1.1.0! Better compatibility, better tested. There are still some problems with IE6 that i would like to have some help with.

1.0.7 is out! With all fixes made by Vasilianskiy Sergey. I've also removed class marking of table rows. Also the plugin doesn't clone the whole table, just thead.

1.0.6 is released with better compatibility with IE6/7. Big thanks to Glen for providing the patches!

1.0.5 is released! Compatibility issues with IE7 and IE8 are still there but since i've limited access to Windows it will take some time to fix them.

I've done some small changes and got the plugin to work with IE8 in all supported modes except (quirks mode). I will create a new release on jquery later today.


Just call floatHeader on a table in the page.

Configuration options

An optional configuration dictionary can be passed to the plugin. Accepted options are:
fadeOutThe length of the fade out animation in ms. Default: 250
faceInThe length of the face in animation in ms. Default: 250
forceClassForces the plugin to use the marker class when searching for a header instead of thead. Default: false
floatClassThe class of the div that contains the floating header. The style should contain an appropriate z-index value. Default: 'floatHeader'
markerClassThe class name that is used for marking which rows that should be floating. Default: floating
cbFadeOutA callback that is called when the floating header should be faded out. The method is called with the wrapped header as argument.
cbFadeInA callback that is called when the floating header should be faded in. The method is called with the wrapped header as argument.
recalculateRecalculate the column width on every scroll event.


The plugin defines two functions on the source table which can be called if the header is changed.
fhRecalculateRecalculated the column width of the floater.
fhInitRecreates the floater from the source table header.

Known issues and bug reporting

Please use the issue tracker on the project page at jquery.com to view and report bugs.


Just want to acknowledge a few people who have contributed to the development.

Diego Arbelaez - Contributed code to support resize events.
Stephen J. Fuhry - A test case for huge tables and testing of the horizontal-scroll-bug.
Glenn Gilbert - Compatibility for IE6/7
Vasilianskiy Sergey - Lots of jQuery fixes

Download and demo

Files can be downloaded at:

A demo can be found at:


Diego Arbelaez said…
Great stuff!... works pretty well in IE7+ and FF3+.. doesnt work on IE6 or Chrome

IE7+ and FF3+ have one minor bug when resizing the browser window, where the header row no longer line up(width wise) with the data rows.

looking forward to an updated version..
Diego Arbelaez said…
Hey Guys, i fixed the issue with the floating header width not matching the width of the data.
Below is the updated code - new stuff is marked with a comment

(edit by Erik) Removed the code to save some space on the page, sorry Diego.
Diego Arbelaez said…
Correction on my notes above, this does in fact work in Google's Chrome, i have a conflict with legacy prototype.js code
Erik said…
Big thanks for the fix, I'll check in the changes in SVN and create a new release at jquery.com.
Duane said…
This script is awesome! I'm using it on a page where the datatable is rendered in a ajax gridview (asp.net) .. If the table is visible before the page load, it works great.

If not - then it doesnt float the headers on the postback - any ideas why? or, if the headers are in float, and there is a ajax postback, the float sticks to the top of the page.
Erik said…
Yes i've also seen this bug, but i did't have time to fix it before my vacation. Please report these issues on the plugin page at jquery.com. I will take a look at them when i get back in the beginning of august :)
Thanks a lot for the feedback
I'm having problems with tables wider than the monitor width.. I'll try and post a demo and run some tests if I get a chance, but for now, here are a couple sample screenshots:
lindsay said…
Anyone else have problems with IE 8?
in IE 8 my table header jumps to the bottom of the screen.
Erik said…
I've created an issue for this bug at jquery.com (http://plugins.jquery.com/project/issues/floatHeader). I'll try to have a look at them as soon as possible, thanks for the input.
alx said…
Same here, IE8 and IE7 not working — headers falling to the footer of the page.
Rivka said…
Doesn't work for me in IE 7 or 8, either. I was really hoping this would work, too!
alx said…
It seems I have found solution for IE 7-8: just add doctype to your document - it will switch explorer to standard-mode and table headers will work like in other browsers.
Erik said…
Thanks, i will verify this workaround today and update this page.
[...] new version can be downloaded from the project page, jQuery or from the subversion [...]
Sam said…
Hey, great script - is it possible to get it to work with tabs?

I have a number of tables in tabs - it works on the first page, then throws an uncaught exception on the other pages and the table header goes nowhere.

I guess it could also be solved by adding a destroy method? That way I could destroy/initialise the floating header as I need it for each tab.

Anyone be able to help with this?

Glenn Gilbert said…
Been using the code on a project that requires IE6 (it's an intranet application). Had to make various fixes for IE and a couple of enhancements. I'll post each fix separately.

Glenn Gilbert said…
Fix 1 - Crashes when using IE6 and IE7

This is caused by the code constantly triggering the $(window).resize event. This is because of a bug in IE's handling of resizing where you have to check document.documentElement.clientHeight/Width.

Above the call to createFloater(table, self, config); add the following two lines:

self.IEWindowWidth = document.documentElement.clientWidth;
self.IEWindowHeight = document.documentElement.clientHeight;

These are local variables to hold the current width and height of the window to test on the event.

The $(window).resize event needs to be replaced with the following:

// bind to the resize event
/* Unfortunately IE gets rather stroppy with the non-IE version, constantly resizing, thus cooking your
* CPU with 100% usage whilst the browser crashes. So, test for IE and add additional code.
if ( $.browser.msie && $.browser.version <= 7 ) {
$(window).resize(function() {
// Check if the window size has changed ()
if ( (self.IEWindowWidth != document.documentElement.clientWidth) || (self.IEWindowHeight != document.documentElement.clientHeight) ) {
// Update the client width and height with the Microsoft version.
self.IEWindowWidth = document.documentElement.clientWidth
self.IEWindowHeight = document.documentElement.clientHeight
createFloater(table, self, config);
} else {
$(window).resize(function() {
// recreate the floating table
createFloater(table, self, config);

Glenn Gilbert said…
Fix 2 - postion:fixed doesn't work with IE6

There's loads written about this where IE6 ignores position:fixed and needs to use position:absolute instead. Unfortunately there's some CSS tricks required to simulate this on IE6.

Most of these have been somewhat documented in Stu Nichols' CSSplay.co.uk website.

In summary you have to move the document scrolling down to the body. This should be done using conditional comments to import the usual IE6 override file. Typically youd' use something like this:

* html { overflow:hidden; }
* html body { height:100%; overflow:scroll; }

Once done, absolute positioning will work like fixed positioning.

The jquery.floatingheader.js file needs to be modified to allow scrolling to be detected on the body as $(window).scroll won't trigger if the CSS was changed as above.

The config needs to have a new flag:

This enables the client to move the scroll detection in IE6 down to the body element.

Replace the line:
$(window).scroll(function() {

With the following:
/* This is very specific to IE6 only if using position:fixed fixes. This requires the window overflow to be set to
* hidden and the containing 'body' tag to have overflow:auto.
if ( !$.browser.msie ) {
config.IE6Fix_DetectScrollOnBody = false;
} else {
if ( $.browser.version > 7) {
config.IE6Fix_DetectScrollOnBody = false;
var scrollElement = config.IE6Fix_DetectScrollOnBody ? $('body') : $(window);
// bind to the scroll event
scrollElement.scroll(function() {

In this function, replace the line:
self.floatBox.css('position', 'fixed');

With the following code:
if ( $.browser.msie && $.browser.version < 7 ) {
// IE6 can't handle fixed positioning; has to use absolute and additional calculation to position correctly
self.floatBox.css('position', 'absolute'); // strictly speaking, this isn't necessary as it is position:absolute
} else {
self.floatBox.css('position', 'fixed');

Erik said…
Good work Glen! I'll merge this in the trunk as soon as i can.
Sergey said…
Some mods to your code:

1) huge table incorect table width. Especialy in FF
fix: target.width(template.outerWidth());
2) everywhere instend of table.children().remove();
fix: better to use table.empty(); //children().remove();
fic: floatRow.empty(); //children().remove();
3) Maybe usefull in some scripts - to not duplicate ids
$('*', target).removeAttr('id');
4) floatBoxVisible not defined
self.floatBoxVisible = false; //after self.floatBox.append(table);
Vasilianskiy Sergey said…
Especialy for IE
inspite of IE TH reports padding = 1, floatCell shoud be set in 0
after floatCell.css('width', cell.width());
fix: if ($.browser.msie) {
floatCell.css('padding', '0 0 0 0');
amit said…

I am not able to make it work on ie6...

ie6 is getting hang on scroll.

Please let me know if i am doing something wrong
Erik said…
@amit I don't know what might be wrong. I will merge the changes suggested by Sergey some time this week. That release might work better with IE6, but that's just a guess...
amit said…
Even demo page is getting hanged on ie6.

Please see...
Erik said…
@amit, unfortunately i don't have access to IE6 so it's hard to fix these issues. I've just integrated Sergeys changes into the plugin. Please try the demo again, if it doesn't work. Contact me on my email, it's on my blogger profile page. Thanks
Vasilianskiy Sergey said…
first of all in 1.0.7 version self.clone() was remove -(
// copy all style and class properties -)
var table = self.clone();

and the second one
// append the floatBox to the dom
// specialy fix for Safari browser
$(window).one('scroll', function() {
createHeader(table, self, config);
and the last one
thanks for include in Contributors
William Shostak said…
The changes in 1.0.7 are great for IE6.

But I agree with Vasilianskiy Sergey put back in the self.clone.
// copy all style and class properties -)
var table = self.clone();

Also I found that in IE (all versions) the header columns to not always size correctly I had to change the code:

floatCell.css('width', cell.width());
if ($.browser.msie) {
floatCell.css('padding', '0 0 0 0');


if ($.browser.msie) floatCell.css('width', cell.outerWidth());
else floatCell.css('width', cell.width());

Nice little plugin thanks for writing it.
Erik said…
Thanks for testing the plugin. I'm not really a JS-developer but i'm learning a lot from all comments and suggestions. I'll put back the self.clone and include a flag for only using the thead instead as an optimization for huge tables.
If you have more issues and/or suggestions you can always contact me through my email which is on my profile page.
Vasilianskiy Sergey said…
some hints to your code to look more beautifie and stable
1) when use console, always check if it presents: not all browsers use right libs. -)
if (console) { console.log("The table contains no header"); };
2) after every command add ;, as not all packers likes \n
example: return;
Vasilianskiy Sergey said…
Finally) Incorect big table th position with floatCell.css('width', cell.outerWidth()); fix: removed
floatCell.css('padding', '0 0 0 0') rules
Erik said…
Oh damn, did i forget a console.log in there? Now that i think about it, i didn't even run it through jslint... I'll have a look at it as soon as possible, thanks.
Unknown said…
I'm having a problem with code. In my setup, I'm having the floating header applied to a div with an overflow. It works flawlessly on that. My issue is that if I apply an update to the contents of the overflow'd div via... say ajax, the code (I'm assuming) loses track of the original floated header. The result is that I get duplicate headers. Outside of size, this normally wouldn't be a huge deal, except once this occurs and I scroll the page scrollbar (not the overflow scrollbar) only the current header seems to get the new positioning... the others (as this happens repeatedly) start scrolling with the page. Any ideas on how to remedy this? Thanks!
Erik said…
The plugin adds the floating header right after the table in the dom. This might have something to do with that?
Please contact me through email, it's on my profile page.
Anonymous said…
Thanks, very nice. Just need this for a CMS so IE support not needed. Works very well.
patrik r said…
Hi, first of all, thanks for a great plugin.

I have tried to implement it in a asp.net application using AJAX. It seems that it has some problems with async programming?

The header works fine the first time I enter a page, but if I click a button on the page or re-sorting a datagrid, I get an javasrcipt error message "Unspecified error", char 35440

I have tried a "clean" asp.net page(.aspx) without any AJAX or updatepanels and then it works fine.
Erik said…
Thanks. Are you using the latest version and are you sure you initialize the plugin on each AJAX load? If so please post a bug report at the jQuery project page at http://plugins.jquery.com/project/floatHeader.
patrik r said…
Hi, this is how I initialize the plugin:

function pageLoad() {
jQuery('#example1').floatHeader ({
fadeIn: 250,
fadeOut: 250

At first I used:
jQuery(document).ready(function() but after some reading on internet I found out that pageLoad is more suitable
Unknown said…
I had to use this code to make it work for me...


$("div.floatHeader #"+id).attr("id","").css("display","").find("tr").attr("id","");
Mike B said…
patrik r, I had that same AJAX issue that you are discussing.

What I ultimately did was every time I refreshed the page I did called the following code:

jQuery(window).unbind(); jQuery("#myTable").floatHeader();

The Error in the Jquery.js script your getting at like 5000something is because basically it is trying to double bind to the window. In IE this is handled as an error. So to correct that just unbind the window before recalling floatHeader().

Hope that helps!
Great plugin, works great for me.

It would be great if you could extend this plugin to do the same with the table footer (e.g. when scrolling up and the footer isn't visible, it gets moved to the bottom of the screen, opposite to the header functionality)
123 said…
Unknown said…
Awesome script guys, thanks very much.

Oddly and contrary to other comments mine worked fine in all browsers I tried except IE7.. even with the demo from this page.

I changed the line:

if ($.browser.msie && $.browser.version <= 7) {

to <= 6 and bingo bango everything works fine.
Anonymous said…
Can I works with different tables. Can I float the header of tabel 1 over table 2?
viMaL said…
i have a table, and on a page load it works gr8.. but i have a filter on top with which i loads again the table... using $.load()

so that time i am losing the floating header :(

is there any solution for this.. please let me know asap. :(
Unknown said…
Hi could you please explain how to you the callbacks?
i just wanna execute a js function but aswell fadein/fadeout the table ..
when i set a cbfadein function it only executes that function but the tbl header isnot floatin anymore.
MickeyVip said…

Thank you for your work!

I have a suggestion - make a plugin work with custom container instead of "window"/"document" (maybe passed as a selector in "options").

It would be nice to have a table placed inside DIV with fixed height and have fixed header, like in WinForms DataGrids.
Version 1.4.0 does not work with IE 8. The floating header appears briefly, like two seconds, and then it disappears forever.
Miggs said…
The script is brilliant. Unfortunately, if I have an extremely wide table, it doesn't recalculate until I scroll vertically. None of the horizontal scrolling triggers the recalculate.
Erik said…
Sorry i'm not really actively developing this plugin anymore. If anyone wants to maintain the code on jquery, i'm all ears
Miggs said…
Drat, that's too bad. Thanks for the response anyway. Any chance you can point me towards a way to call the recalculate the positioning from my own function? Sorry, my .js skills are not spectacular.
Erik said…
Try to start with this method: https://github.com/bysse/JQuery-Floating-Header-Plugin/blob/master/js/jquery.floatheader.js#L247

You can contact me through email on my blogger profile i think...
Miggs said…
Thank you for following up. I could not get to your profile in blogger.

If you don't have time for this, let me know and I will try to make do. I think all I need to do is add a detect for horizontal scroll and fire the recalculate on that as well. I can't seem to figure out where/how to do this.

Thanks again, you are tops.
Anonymous said…
Nice job! This plugin is just exactly what I was looking for, and it works perfectly.
Unknown said…
Your demo link not even working
Kelly Shipp said…
Demo link is dead. So is this plugin.
Mikhail Koryak said…
i wrote a plugin that works with all latest browsers and ie7, but also supports full page scrolling:


Popular posts from this blog

Cubing for charity #4

Seascape - OpenVR adaptation of a 4k intro