How 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. Want to “fix a table row or column” in HTML? Only to find out that there are no direct ways in HTML?

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

  1. Limit the height of the table body and set it to auto overflow.
    • thead, tbody { display: block; }
    • tbody { max-height: 100px; overflow: auto; }
  2. Set a sticky table header – th { 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 the detailed examples!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

 

QUICK SLIDES

 

TABLE OF CONTENTS

Download & Notes Freeze Row Column Useful Bits & Links
The End

 

DOWNLOAD & NOTES

Firstly, here is the download link to the example code as promised.

 

EXAMPLE CODE DOWNLOAD

Click here to download all the example source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

QUICK NOTES

If you spot a bug, please feel free to comment below. I try to answer questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

 

FREEZE TABLE ROWS & COLUMNS

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

 

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: 150px;
  overflow: auto;
}

/* (C) 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 1</th><th>Head 2</th></tr>
  </thead>
  <tbody>
    <tr><td>Cell 1</td><td>Cell 2</td></tr>
    <tr><td>Cell 1</td><td>Cell 2</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; }

 

 

2) STICKY HEADER

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

/* (B) 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 1</th><th>Head 2</th></tr>
  </thead>
  <tbody>
    <tr><td>Cell 1</td><td>Cell 2</td></tr>
    <tr><td>Cell 1</td><td>Cell 2</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. Personally, I think this is better and more elegant.

 

 

3) FREEZE COLUMN

3-sticky-column.html
<style>
/* (A) TABLE WRAPPER */
#demoCW {
  width: 100%;
  overflow: auto;
}
 
/* (B) STICKY HEADERS */
#demoCT th {
  position: sticky;
  left: 0;
  z-index: 2;
}
 
/* (C) 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
  • Look no further, this is the same old position: sticky, except that we set it to left: 0 instead.
  • Also, the first cell of each row is a <th>.

 

 

4) FREEZE ROW & COLUMN

4-row-col.html
<style>
/* (A) TABLE WRAPPER */
#demoDW {
  width: 100%;
  max-height: 200px;
  overflow: auto;
}
 
/* (B) STICKY HEADERS */
#demoDT th {
  position: sticky;
  top: 0;
  z-index: 2;
}
#demoDT th[scope=row] {
  left: 0;
  z-index: 1;
}
 
/* (C) COSMETICS - NOT IMPORTANT */
#demoDT th, #demoDT td {
  font-size: 20px;
  padding: 10px;
  text-align: left;
  min-width: 300px;
}
#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 scope="row">Head</th>
      <td>Cell</td><td>Cell</td><td>Cell</td>
    </tr>
    <tr>
      <th scope="row">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

Lastly, how do we stick both the header row and first column? Keep calm and look closely – This is just a combination of using position: sticky on both the header and first column.

 

 

USEFUL BITS & LINKS

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

 

LINKS & REFERENCES

 

INFOGRAPHIC CHEAT SHEET

Freeze HTML Table Row & Column (click to enlarge)

 

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!

Leave a Comment

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