Sticky table header with jQuery

When you want the table headers to always stay around (e.g. because that table is huuuge), use the code below.

Style

table.fixed_table_header{
  position: fixed;
  top: 0;
  width: auto;
  display: none;
  border: none;
  margin: 0;
}

Javascript

;(function($) {
   $.fn.fixHeader = function() {
      return this.each(function() {
         var $table = $(this),
            $t_fixed;

         function init() {
            $t_fixed = $table.clone();
            $t_fixed.find('tbody').remove().end().addClass('fixed_table_header').insertBefore($table);
            resizeFixed();
         }

         function resizeFixed() {
            $t_fixed.find("th").each(function(index) {
               $(this).css("min-width",$table.find("th").eq(index).width()+"px");
            });
         }

         function scrollFixed() {
            var offset = $(this).scrollTop(),
            tableOffsetTop = $table.offset().top,
            tableOffsetBottom = tableOffsetTop + $table.height() - $table.find("thead").height();
            if(offset < tableOffsetTop || offset > tableOffsetBottom)
               $t_fixed.hide();
            else if(offset >= tableOffsetTop && offset <= tableOffsetBottom && $t_fixed.is(":hidden"))
               $t_fixed.show();

            // left-align $t_fixed with $table
            $t_fixed.css("left", $table.offset().left - $(this).scrollLeft());
         }

         $(window).resize(resizeFixed);
         $(window).scroll(scrollFixed);

         init();
      });
   };
})(jQuery);

The init function clones the table, throws away the table body, hides the clone and inserts it before the actual table. Then it "manually" sets the width of the clone's elements to those of the actual table. Whenever the user scrolls, the clone is hidden or shown appropriately and scrolled horizontally.

This is an improvement of this codepen Show archive.org snapshot .

Dominik Schöler Almost 10 years ago