How to freeze the first row and the first column of an HTML table with CSS, Javascript and JQuery

how to freeze the first row and the first column of an HTML table
Blog Problem Solving Tutorial

This tutorial shows how to block the first row and the first column on scrolling of a table using CSS and JQuery

I was working on an HTML table that displays a list of users and user permission, the first row displays the permission names and the first column displays the name of the users involved. I have noticed that when I strolled toward the right I couldn’t see the user names and scrolling toward the bottom of the table the user permissions disappeared from the top of the table.

So I had the necessity to block the first row of the table and the first column of the table in order to always show the user names and the user permissions.

Freeze the first row or header of a HTML table in CSS.

Freezing the first row of an HTML table is quite simple, to do that we just need to use the tag <thead> and  <tbody> inside our HTML table in order to recognize the header of the table with the body and the values of the same table. In this way, we can easily block the first row of the table. Here is a table sample:


In this case, we just need to block the height of <tbody> in CSS and we also need to modify the style of <tbody> to display the table block with <display: block>. The propriety <overflow: auto> will help to display the scrollbar automatically. Unfortunately using this property we lose the possibility to create a fully responsive table suitable for any device. In order to make the table responsive, we have to be sure to fix the width of any cell and any header cell, otherwise, the table value won’t match with the table header. Here is the CSS for this purpose:

table {
    display: block;
    width: 50em;
    max-width: 100%;
    position: relative;
    overflow-x: auto;
/* block the table height and display the scrollbar */
tbody {
    height: 200px;
    overflow: auto;
    display: block;
/* fix the cell width */ 
th, td {
    width: 3.5em;

Block the first row of an HTML table with JQuery

Now that we know how to freeze a part of the table and how to create a responsive scroll, we need to dynamically block the part of the table that we want to block, in my case the first row and the first column. Unfortunately, CSS can only block rows OR columns, but it can’t block both at the same time. So, please forget the CSS above if you want to block a row and a column of your table at the same time.

What we need to do is trick the CSS and create a JQuery function that simulates the freeze of the row/column during the scrolling. To do this we will use the JS functions scrollTop and scrollLeft, these functions return the number of pixels of the scroll. For more information, please have a look at the official documentation following this link.

First of all, we need to identify the HTML table through an ID, for example <table id="fixed-headers">. Then I need to connect our HTML table with the scroll javascript event in order to run my JS script only during the table scroll. Now I need to create a function that transports the header to the top based on the number of pixels on the axis Y (we just need to move the header up and down). Here is the code:

$('thead').css('transform', 'translateY(' + this.scrollTop + 'px)');

Now I create a function that transports the first column on scroll, this time the column will be transported on the axis X, in other words, we are moving the column left and right. Here is the code:

$('tbody th').css('transform', 'translateX(' + this.scrollLeft + 'px)');

Now I need to assemble the code above with this CSS:

/* style the HTML table */
table {
    display: block;
    width: 50em;
    max-width: 100%;
    position: relative;
/* this will active the scrollbar */
#fixed-headers {
  border-collapse: collapse;
  height: 300px; 
  display: block; 
  overflow: auto; 
/* force the cells to have the same width */
#fixed-headers td {
  padding: 0 4em !important; 
  border: 1px solid #eee  !important;
#fixed-headers thead {
  transform: translateZ(0);
#fixed-headers thead th {
    background: #999;
    text-align: center;
#fixed-headers tbody th {
    text-align: right;
    background: #999;
    transform: translateZ(0);

Here is the final JQuery code:

$(function() {
  $('#fixed-headers').scroll(function(ev) {
     * where the table scroll, change the position of header and first column
    $('thead th').css('transform', 'translateY(' + this.scrollTop + 'px)');
    $('tbody th').css('transform', 'translateX(' + this.scrollLeft + 'px)');

And here is the final result:


To see the whole code in action, please have a look at this task on CodePen at this link:

Click to Leave a Comment

You May Like

How to animate HTML elements and slide them in on mouse scroll using CSS and Javascript Today I want to animate a bunch of HTML elements and create an animation that moves them inside the same parent DIV once the elements are in the viewport, so only when the elements are visible to the users. […]

August 29, 2023

This tutorial will show you how to change your website cursor to any CSS shape and change the shape on hover on certain HTML elements. I have seen a lot of tutorials online about changing the HTML cursor to an SVG icon or to a PGN icon. In my case, I would like to change […]

October 15, 2022

Woocommerce Min Max Checkout is a plugin that extends your Woocommerce e-commerce in order to give you the possibility to set the minimum or maximum checkout amount or in order to set a minimum or maximum order quantity on the cart or checkout pages. With Woocommerce Min Max Checkout you can also set e customizable […]

February 12, 2022