24

I want to make header of my table fixed. Table is present inside the scrollable div. Below is my code.

<div id="table-wrapper">
    <div id="table-scroll">
        <table bgcolor="white" border="0" cellpadding="0" cellspacing="0" id="header-fixed" width="100%" overflow="scroll" class="scrollTable">
            <thead>
                <tr>
                    <th>Order ID</th>
                    <th>Order Date</th>
                    <th>Status</th>
                    <th>Vol Number</th>
                    <th>Bonus Paid</th>
                    <th>Reason for no Bonus</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><%=snd.getOrderId()%></td>
                    <td><%=snd.getDateCaptured()%></td>
                    <td><%=snd.getOrderStatus()%></td>
                    <td>Data Not Available</td>
                    <td>Data Not Available</td>
                    <td>Data Not Available</td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

Below is my CSS, which I am using for the above div:

#table-wrapper {
    position:relative;
}

#table-scroll {
    height:250px;
    overflow:auto;  
    margin-top:20px;
}

#table-wrapper table {
    width:100%;
}

#table-wrapper table * {
    background:white;
    color:black;
}

#table-wrapper table thead th .text {
    position:absolute;   
    top:-20px;
    z-index:2;
    height:20px;
    width:35%;
    border:1px solid red;
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
Rohan
  • 521
  • 4
  • 9
  • 24
  • What do you mean by "make header of my table fixed"? Is it supposed to always be visible despite scrolling down? – Mario Jul 24 '13 at 07:44
  • @Mario exactly top row of table should always visible – Rohan Jul 24 '13 at 07:58
  • Ive just added an answer to a similar question that may help http://stackoverflow.com/questions/31433833/fix-table-header-at-top-of-scrollable-div/31434590#31434590 – Tony Ray Tansley Jul 16 '15 at 07:07

11 Answers11

33

How about doing something like this? I've made it from scratch...

What I've done is used 2 tables, one for header, which will be static always, and the other table renders cells, which I've wrapped using a div element with a fixed height, and to enable scroll, am using overflow-y: auto;

Also make sure you use table-layout: fixed; with fixed width td elements so that your table doesn't break when a string without white space is used, so inorder to break that string am using word-wrap: break-word;

Demo

.wrap {
    width: 352px;
}

.wrap table {
    width: 300px;
    table-layout: fixed;
}

table tr td {
    padding: 5px;
    border: 1px solid #eee;
    width: 100px;
    word-wrap: break-word;
}

table.head tr td {
    background: #eee;
}

.inner_table {
    height: 100px;
    overflow-y: auto;
}

<div class="wrap">
    <table class="head">
        <tr>
            <td>Head 1</td>
            <td>Head 1</td>
            <td>Head 1</td>
        </tr>
    </table>
    <div class="inner_table">
        <table>
        <tr>
            <td>Body 1</td>
            <td>Body 1</td>
            <td>Body 1</td>
        </tr>
        <!-- Some more tr's -->
    </table>
    </div>
</div>
Mr. Alien
  • 153,751
  • 34
  • 298
  • 278
  • hi.. this doesn't work if the columns are say 40 columns.. and need to scroll from right and left.. as well as top and bottom... the column header need to be fixed and that too inside a scrollable div. anyone has a solution... see full posting in here: http://stackoverflow.com/questions/22093319/large-html-table-with-fixed-header-inside-scrollable-div-how – ihightower Mar 03 '14 at 16:13
  • 4
    You've placed static widths on the table columns, which is pretty much the entire point of using tables to display content in the first place. This isn't a solution at all. Why even bother w/ a table if you're just going to have fixed widths? Why not just use divs? – RavenHursT Apr 28 '14 at 21:37
  • 5
    @RavenHursT because the `` element is great for tabular data, which it seems the OP has.
    – mikedidthis Apr 29 '14 at 09:40
  • 1
    But the only point of using a table for tabular data is so that the browser is tasked with calculating the width of the columns. If you're forcing a fixed with, you'd have better performance with divs. Tables have a large amount of rendering overhead. A correct solution would be to have the table still render as a table with the only change being a fixed header row... Which, admittedly, I still haven't found a complete solution for. Hence the reason I'm here trolling this answer ;-) – RavenHursT Apr 29 '14 at 16:19
  • 1
    @RavenHursT sadly I have to disagree. I think the CSS property `table-layout: fixed;` does too. – mikedidthis Apr 29 '14 at 19:23
  • @Mahi Yes, cuz OP requested for Y scroll – Mr. Alien Feb 24 '17 at 20:17
21

Using position: sticky on th will do the trick.

Note: if you use position: sticky on thead or tr, it won't work.

https://jsfiddle.net/hrg3tmxj/

Tenzin Nyima
  • 211
  • 2
  • 2
  • 2
    I'm not sure why this was downvoted. This solution did the job for my needs with far less "compromise" than other solutions. One thing I will note is that the th elements will need a background-color. – JSager Feb 17 '19 at 05:30
  • 4
    Late, but wanted to comment for others that this is by far and away the simplest and best solution. None of that "hacky" nonsense that takes 20 lines of CSS to get to work. Simply do as indicated, and don't forget to put Top: 0 as well. – haag1 Nov 25 '19 at 15:19
  • 2
    Logged in to StackOverflow for the first time in 3 years just to comment this. THIS IS LITERALLY THE EASIEST SOLUTION TO GET A FIXED HEADER ON A TABLE. – Anvay Nov 03 '20 at 06:27
4

Some of these answers seem unnecessarily complex. Make your tbody:

display: block; height: 300px; overflow-y: auto

Then manually set the widths of each column so that the thead and tbody columns are the same width. Setting the table's style="table-layout: fixed" may also be necessary.

EricP
  • 3,395
  • 3
  • 33
  • 46
4

None of the other examples provided worked in my case - e.g. header would not match table body content when scrolling. I found a much simpler and clean way, allowing you to setup the table the normal way, and without too much code.

Example:

.table-wrapper{
  overflow-y: scroll;
  height: 100px;
}

.table-wrapper th{
    position: sticky;
    top: 0;
    background-color: #FFF;
}
<div class="table-wrapper">
    <table>
        <thead>
            <tr>
                <th>Header 1</th>
                <th>Header 2</th>
                <th>Header 3</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td>Text</td>
                <td>Text</td>
                <td>Text</td>
            </tr>
            <tr>
                <td>Text</td>
                <td>Text</td>
                <td>Text</td>
            </tr>
            <tr>
                <td>Text</td>
                <td>Text</td>
                <td>Text</td>
            </tr>
            <tr>
                <td>Text</td>
                <td>Text</td>
                <td>Text</td>
            </tr>
            <tr>
                <td>Text</td>
                <td>Text</td>
                <td>Text</td>
            </tr>
            <tr>
                <td>Text</td>
                <td>Text</td>
                <td>Text</td>
            </tr>
            <tr>
                <td>Text</td>
                <td>Text</td>
                <td>Text</td>
            </tr>
        </tbody>
    </table>
</div>

Thanks to https://algoart.fr/articles/css-table-fixed-header

FooBar
  • 5,752
  • 10
  • 44
  • 93
  • For some reason if I do this with my tables, the header sticks to only to the main document, but not to the div. – Sebi2020 May 13 '22 at 10:21
  • I liked this answer, simple, no need to make a lot :) I've changed the height -> height: 85vh; to have my table on the full page minus my header – WannaGetHigh Nov 04 '22 at 14:05
3

I think you need something like this ?

Like this

.....
<style>
.table{width: 500px;height: 200px;border-collapse:collapse;}
.table-wrap{max-height: 200px;width:100%;overflow-y:auto;overflow-x:hidden;}
.table-dalam{height:300px;width:500px;border-collapse:collapse;}
.td-nya{border-left:1px solid white;border-right:1px solid grey;border-bottom:1px solid    grey;}

</style>

<table class="table">
<thead>
    <tr>
    <th>Judul1</th>
    <th>Judul2</th>
    <th>Judul3</th>
    <th>Judul4</th>
   </tr>
 </thead>
 <tbody>
   <tr>
      <td colspan="4">
      <div class="table-wrap" >
      <table class="table-dalam">
         <tbody>
             <?php foreach(range(1,10) as $i): ?>
                 <tr >
                     <td class="td-nya">td1 </td>
                     <td class="td-nya">td2</td>
                     <td class="td-nya">td2</td>
                     <td class="td-nya">td2</td>
                 </tr> 
            <?php endforeach;?>
        </tbody>
       </table>
     </div>
   </td>
 </tr>
  </tbody>
 </table>

Source

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
jsdev
  • 672
  • 6
  • 14
  • 2
    This seems to work well for fixed-width columns. If your header columns widths are dependent on the data in them this solution doesn't work very well. Still, +1 for the idea. – BrianLegg Jul 21 '15 at 19:34
1

I needed the same and this solution worked the most simple and straightforward way:

http://www.farinspace.com/jquery-scrollable-table-plugin/

I just give an id to the table I want to scroll and put one line in Javascript. That's it!

By the way, first I also thought I want to use a scrollable div, but it is not necessary at all. You can use a div and put it into it, but this solution does just what we need: scrolls the table.

adamvagyok
  • 165
  • 1
  • 2
  • 8
1

This is my "crutches" solution by using html and css. There used 2 tables and fixed width of tables and table cell`s

https://jsfiddle.net/babaikawow/s2xyct24/1/

HTML:

  <div class="container">
<table class="table" border = 1; >  <!-- fixed width header -->
                            <thead >
                                <tr>
                                    <th class="tbDataId" >№</th>
                                    <th class="tbDataName">Працівник</th>
                                    <th class="tbDataData">Дата</th>
                                    <th class="tbDataData">Дійсно до</th>
                                    <th class="tbDataDiseases">Критерій1</th>
                                    <th class="tbDataDiseases">Критерій2</th>
                                    <th class="tbDataDiseases">Критерій3</th>
                                    <th class="tbDataDiseases">Критерій4</th>
                                    <th class="tbDataDiseases">Критерій5</th>  
                                </tr>
                            </thead>  
                        </table> 

                        <div class="scrollTable"> <!-- scrolling block -->
                            <table class="table" border = 1;>
                                 <tbody>
                   <tr>
                      <td class="tbDataId" >№</td>
                                    <td class="tbDataName">Працівник</td>
                                    <td class="tbDataData">Дата</td>
                                    <td class="tbDataData">Дійсно до</td>
                                    <td class="tbDataDiseases">Критерій1</td>
                                    <td class="tbDataDiseases">Критерій2</td>
                                    <td class="tbDataDiseases">Критерій3</td>
                                    <td class="tbDataDiseases">Критерій4</td>
                                    <td class="tbDataDiseases">Критерій5</td> 
                   </tr>
                    <tr>
                      <td class="tbDataId" >№</td>
                                    <td class="tbDataName">Працівник</td>
                                    <td class="tbDataData">Дата</td>
                                    <td class="tbDataData">Дійсно до</td>
                                    <td class="tbDataDiseases">Критерій1</td>
                                    <td class="tbDataDiseases">Критерій2</td>
                                    <td class="tbDataDiseases">Критерій3</td>
                                    <td class="tbDataDiseases">Критерій4</td>
                                    <td class="tbDataDiseases">Критерій5</td> 
                   </tr>
                    <tr>
                      <td class="tbDataId" >№</td>
                                    <td class="tbDataName">Працівник</td>
                                    <td class="tbDataData">Дата</td>
                                    <td class="tbDataData">Дійсно до</td>
                                    <td class="tbDataDiseases">Критерій1</td>
                                    <td class="tbDataDiseases">Критерій2</td>
                                    <td class="tbDataDiseases">Критерій3</td>
                                    <td class="tbDataDiseases">Критерій4</td>
                                    <td class="tbDataDiseases">Критерій5</td> 
                   </tr>
                    <tr>
                      <td class="tbDataId" >№</td>
                                    <td class="tbDataName">Працівник</td>
                                    <td class="tbDataData">Дата</td>
                                    <td class="tbDataData">Дійсно до</td>
                                    <td class="tbDataDiseases">Критерій1</td>
                                    <td class="tbDataDiseases">Критерій2</td>
                                    <td class="tbDataDiseases">Критерій3</td>
                                    <td class="tbDataDiseases">Критерій4</td>
                                    <td class="tbDataDiseases">Критерій5</td> 
                   </tr>
                    <tr>
                      <td class="tbDataId" >№</td>
                                    <td class="tbDataName">Працівник</td>
                                    <td class="tbDataData">Дата</td>
                                    <td class="tbDataData">Дійсно до</td>
                                    <td class="tbDataDiseases">Критерій1</td>
                                    <td class="tbDataDiseases">Критерій2</td>
                                    <td class="tbDataDiseases">Критерій3</td>
                                    <td class="tbDataDiseases">Критерій4</td>
                                    <td class="tbDataDiseases">Критерій5</td> 
                   </tr>
                                </tbody>
                            </table>
                        </div> 
</div>

CSS:

*{
  box-sizing: border-box;
}

.container{
 width:1000px;
}
.scrollTable{

    overflow: scroll;
  overflow-x: hidden;
    height: 100px;
} 
table{
margin: 0px!important;
width:983px!important;
border-collapse: collapse; 

}

/*   Styles of the th and td  */

/* Id */
.tbDataId{
    width:5%;
}

/* Дата,
Дійсно до */
.tbDataData{
    /*width:170px;*/
    width: 15%;
}

/* П І Б */
.tbDataName{
    width: 15%;
}

/*Критерії */
.tbDataDiseases{
    width:10%;
}
Babaikawow
  • 69
  • 6
0

A Fiddle would have been more helpful nevertheless from what I understand, I guess what you need is persistent headers, look into this

http://css-tricks.com/persistent-headers/

Sam
  • 139
  • 1
0

This code works form me. Include the jquery.js file.

<!DOCTYPE html>
<html>

<head>
<script src="jquery.js"></script>
<script>
var headerDivWidth=0;
var contentDivWidth=0;
function fixHeader(){

var contentDivId = "contentDiv";
var headerDivId = "headerDiv";

var header = document.createElement('table');
var headerRow = document.getElementById('tableColumnHeadings'); 

/*Start : Place header table inside <DIV> and place this <DIV> before content table*/
var headerDiv = "<div id='"+headerDivId+"' style='width:500px;overflow-x:hidden;overflow-y:scroll' class='tableColumnHeadings'><table></table></div>";
$(headerRow).wrap(headerDiv);
$("#"+headerDivId).insertBefore("#"+contentDivId);
/*End : Place header table inside <DIV> and place this <DIV> before content table*/

fixColumnWidths(headerDivId,contentDivId);
}
function fixColumnWidths(headerDivId,contentDivId){
 /*Start : Place header row cell and content table first row cell inside <DIV>*/ 
            var contentFirstRowCells = $('#'+contentDivId+' table tr:first-child td');
            for (k = 0; k < contentFirstRowCells.length; k++) {
                $( contentFirstRowCells[k] ).wrapInner( "<div ></div>");
            }
            var headerFirstRowCells = $('#'+headerDivId+' table tr:first-child td');
            for (k = 0; k < headerFirstRowCells.length; k++) {
                $( headerFirstRowCells[k] ).wrapInner( "<div></div>");
            }
 /*End : Place header row cell and content table first row cell inside <DIV>*/ 

 /*Start : Fix width for columns of header cells and content first ror cells*/
            var headerColumns = $('#'+headerDivId+' table tr:first-child td div:first-child');
            var contentColumns = $('#'+contentDivId+' table tr:first-child td div:first-child');
            for (i = 0; i < contentColumns.length; i++) {
                if (i == contentColumns.length - 1) {
                    contentCellWidth = contentColumns[i].offsetWidth;
                }
                else {
                    contentCellWidth = contentColumns[i].offsetWidth;
                }
                headerCellWidth = headerColumns[i].offsetWidth;
                if(contentCellWidth>headerCellWidth){
                $(headerColumns[i]).css('width', contentCellWidth+"px");
                $(contentColumns[i]).css('width', contentCellWidth+"px");
                }else{
                $(headerColumns[i]).css('width', headerCellWidth+"px");
                $(contentColumns[i]).css('width', headerCellWidth+"px");
                }
            }
/*End : Fix width for columns of header and columns of content table first row*/
}   

    function OnScrollDiv(Scrollablediv) {
    document.getElementById('headerDiv').scrollLeft = Scrollablediv.scrollLeft;
    }
function radioCount(){
    alert(document.form.elements.length);

}   
</script>
<style>
table,th,td
{
border:1px solid black;
border-collapse:collapse;
}
th,td
{
padding:5px;
}
</style>

</head>

<body onload="fixHeader();">
<form id="form" name="form">
<div id="contentDiv" style="width:500px;height:100px;overflow:auto;" onscroll="OnScrollDiv(this)">
<table>
<!--tr id="tableColumnHeadings" class="tableColumnHeadings">
  <td><div>Firstname</div></td>
  <td><div>Lastname</div></td>      
  <td><div>Points</div></td>
  </tr>

<tr>
  <td><div>Jillsddddddddddddddddddddddddddd</div></td>
  <td><div>Smith</div></td>     
  <td><div>50</div></td>
  </tr-->

  <tr id="tableColumnHeadings" class="tableColumnHeadings">
  <td>&nbsp;</td>

  <td>Firstname</td>
  <td>Lastname</td>     
  <td>Points</td>
  </tr>

<tr style="height:0px">
<td></td>
  <td></td>
  <td></td>     
  <td></td>
  </tr>

<tr >
<td><input type="radio" id="SELECTED_ID" name="SELECTED_ID" onclick="javascript:radioCount();"/></td>
  <td>Jillsddddddddddddddddddddddddddd</td>
  <td>Smith</td>        
  <td>50</td>
  </tr>

<tr>
<td><input type="radio" id="SELECTED_ID" name="SELECTED_ID"/></td>

  <td>Eve</td>
  <td>Jackson</td>      
  <td>9400000000000000000000000000000</td>
</tr>
<tr>
<td><input type="radio" id="SELECTED_ID" name="SELECTED_ID"/></td>

  <td>John</td>
  <td>Doe</td>      
  <td>80</td>
</tr>
<tr>
<td><input type="radio" id="SELECTED_ID" name="SELECTED_ID"/></td>

  <td><div>Jillsddddddddddddddddddddddddddd</div></td>
  <td><div>Smith</div></td>     
  <td><div>50</div></td>
  </tr>
<tr>
<td><input type="radio" id="SELECTED_ID" name="SELECTED_ID"/></td>

  <td>Eve</td>
  <td>Jackson</td>      
  <td>9400000000000000000000000000000</td>
</tr>
<tr>
<td><input type="radio" id="SELECTED_ID" name="SELECTED_ID"/></td>

  <td>John</td>
  <td>Doe</td>      
  <td>80</td>
</tr>
</table>
</div>

</form>
</body>

</html>
bjb568
  • 11,089
  • 11
  • 50
  • 71
0

use StickyTableHeaders.js for this.

Header was transparent . so try to add this css .

thead {
    border-top: none;
    border-bottom: none;
    background-color: #FFF;
}
Saajan
  • 670
  • 1
  • 9
  • 20
0

I know this question is old, but if anyone have this same issue, an easy way without having to write lots of CSS, just wrap your <table> with <div> and your <div> should have a style with overflow-y: auto; and some height.
As below example:

<div style="overflow-y: auto; height: 400px;">
 <table>...</table>
</div>

Add a style to the thead as below:

thead {
  position: sticky;
  top: 0;z-index: 2;
}
Robin V.
  • 1,484
  • 18
  • 30
Cito
  • 26
  • 6