4 Ways To Freeze Rows & Columns Of HTML Tables (Simple Examples)

Welcome to a quick tutorial and examples on how to freeze rows and columns in HTML tables. Need to “fix a table row or column”? Only to find out that there are no direct ways to do so in HTML and CSS?

The possible ways to freeze a row/column in HTML and CSS are:

  1. Limit the height of the table body and set it to overflow.
    • thead, tbody { display: block; }
    • tbody { max-height: 100px; overflow: auto; }
  2. Set a sticky table header – thead { position: sticky; top: 0; }
  3. To freeze a column:
    • Set the first cell of the row as a header – <tr> <th>HEAD</th> <td>CELL</td><td>CELL</td> </tr>
    • Set the header cell to stick – th { position: sticky; left: 0; }

That covers the quick basics, but read on for detailed examples!

 

 

TABLE OF CONTENTS

 

DOWNLOAD & NOTES

Here is the download link to the example code, so you don’t have to copy-paste everything.

 

EXAMPLE CODE DOWNLOAD

Click here to download | Example on CodePen

Just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

SORRY FOR THE ADS...

But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.

Buy Me A Coffee Code Boxx eBooks

 

 

FREEZE TABLE ROWS & COLUMNS

All right, let us now get the various possible ways to freeze the table rows and columns in HTML.

 

TUTORIAL VIDEO

 

METHOD 1) FREEZE HEADER ROW WITH OVERFLOW

1-overflow.html
<style>
/* (A) DISPLAY AS BLOCK */
#demoA thead, #demoA tbody { display: block; }

/* (B) LIMIT HEIGHT & SET OVERFLOW */
#demoA tbody {
  max-height: 200px;
  overflow: auto;
}

/* (X) COSMETICS - NOT IMPORTANT */
#demoA { width:100%; }
#demoA th, #demoA td {
  width: 100px;
  font-size: 20px;
  padding: 10px;
  text-align: left;
}
#demoA thead { background: #ffebec; }
#demoA tbody { background: #e4ebff; }
</style>
 
<table id="demoA">
  <thead>
    <tr><th>Head</th><th>Head</th></tr>
  </thead>
  <tbody>
    <tr><td>Cell</td><td>Cell</td></tr>
    <tr><td>Cell</td><td>Cell</td></tr>
  </tbody>
</table>
Head Head
Cell Cell
Cell Cell
Cell Cell
Cell Cell
Cell Cell

This seems to be a common solution on the Internet. It is not the prettiest, but at least it is simple and it works.

  • Just set the head and body sections of the table to display: block.
  • Then limit the height of the table body, set it to auto overflow tbody { max-height: XYZpx; overflow: auto; }

 

 

METHOD 2) STICKY HEADER

2-sticky-header.html
/* (A) STICKY HEADER */
#demoB thead {
  position: sticky;
  top: 0;
  z-index: 2;
}

/* (X) COSMETICS - NOT IMPORTANT */
#demoB { width:100%; }
#demoB th, #demoB td {
  font-size: 20px;
  padding: 10px;
  text-align: left;
}
#demoB th { background: #ffebec; }
#demoB td { background: #e4ebff; }
</style> 
 
<table id="demoB">
  <thead>
    <tr><th>Head</th><th>Head</th></tr>
  </thead>
  <tbody>
    <tr><td>Cell</td><td>Cell</td></tr>
    <tr><td>Cell</td><td>Cell</td></tr>
  </tbody>
</table>
Head Head
Cell Cell
Cell Cell
Cell Cell
Cell Cell
Cell Cell

This is an alternative to the previous method, where we set the table header to position: sticky. I think this is more elegant – Modern browsers “automatically understand” this, and will make the header follow as you scroll down.

 

 

METHOD 3) FREEZE COLUMN

3-sticky-column.html
<style>
/* (A) TABLE WRAPPER */
#demoCW { overflow: auto; }
 
/* (B) STICKY HEADERS */
#demoCT th {
  position: sticky;
  left: 0;
  z-index: 2;
}
 
/* (X) COSMETICS - NOT IMPORTANT */
#demoCT th, #demoCT td {
  font-size: 20px;
  padding: 10px;
  text-align: left;
  min-width: 300px;
}
#demoCT th { background: #ffebec; }
#demoCT td { background: #e4ebff; }
</style>
 
<div id="demoCW"><table id="demoCT">
  <tr>
    <th>Head</th>
    <td>Cell</td><td>Cell</td><td>Cell</td>
  </tr>
  <tr>
    <th>Head</th>
    <td>Cell</td><td>Cell</td><td>Cell</td>
  </tr>
</table></div>
Head Cell Cell Cell
Head Cell Cell Cell
Head Cell Cell Cell
Head Cell Cell Cell
Head Cell Cell Cell

Slightly more roundabout to freeze columns.

  • Create a wrapper with overflow: auto around the table.
  • Set the first cell of each row to <th>.
  • Lastly, set the header cells to position: sticky, but to left: 0 this time.

 

 

METHOD 4) FREEZE ROW & COLUMN

4-row-col.html
<style>
/* (A) TABLE WRAPPER */
#demoDW {
  max-height: 200px;
  overflow: auto;
}
 
/* (B) STICKY HEADERS */
#demoDT thead, #demoDT th { position: sticky; }
#demoDT thead { top: 0; z-index: 2; }
#demoDT th { left: 0; z-index: 1; }
 
/* (X) COSMETICS - NOT IMPORTANT */
#demoDT th, #demoDT td {
  font-size: 20px;
  padding: 10px;
  text-align: left;
  min-width: 300px;
}
#demoDT thead th { background: #b7ffd5; }
#demoDT th { background: #ffebec; }
#demoDT td { background: #e4ebff; }
</style>

<div id="demoDW"><table id="demoDT">
  <thead>
    <tr>
      <th>Head</th><th>Head</th>
      <th>Head</th><th>Head</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>Head</th>
      <td>Cell</td><td>Cell</td><td>Cell</td>
    </tr>
    <tr>
      <th>Head</th>
      <td>Cell</td><td>Cell</td><td>Cell</td>
    </tr>
  </tbody>
</table></div>
Head Head Head Head
Head Cell Cell Cell
Head Cell Cell Cell
Head Cell Cell Cell
Head Cell Cell Cell
Head Cell Cell Cell

To freeze both the header row and first column, this is pretty much a combination of the previous examples.

  • Create a wrapper with overflow: auto around the table.
  • Same old tactic – Set the first header row in <thead>, and the first cell of each row to <th>.
  • Set sticky on both <thead> and <th>.
  • But take note of the order here, <thead> is on top of <th>. If you want the other way, swap the z-index accordingly.

 

 

EXTRAS

That’s all for the tutorial, and here is a small section on some extras and links that may be useful to you.

 

INFOGRAPHIC CHEATSHEET

Free Table Rows & Columns In HTML  CSS (Click To Enlarge)

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end. I hope that it has helped you to better understand, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!

4 thoughts on “4 Ways To Freeze Rows & Columns Of HTML Tables (Simple Examples)”

  1. For method 4) freeze row & column, the horizontal scroll of the headers needs an additional CSS statement:
    #demoDT thead th:first-child { z-index: 3; }
    in order for the header of the left column to stay above the headers of the other columns

Leave a Comment

Your email address will not be published. Required fields are marked *