2

I have a html page with some content on top and table below. How to make the top content and head of table fixed on page and enable only data rows to scroll?

I find only very complicated solutions with javascript, but I wonder does exist some simpler way to do that. The html page is like this:

    <div>
      top content
    </div>
    <table>
      <thead>
        <tr><th> ... first header row
        <tr><th> ... second header row
      </thead>
      <tbody>
        ... data rows
      </tbody>
    </table>
Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
Zoran
  • 21
  • 1
  • 2

3 Answers3

2

Give position: sticky; top: 0; to your th elements. Or you can give fix height to your tbody and add overflow-y:auto

.tableFixHead {
  overflow: auto;
  height: 80vh;
}
.tableFixHead thead th {
  position: sticky;
  top: 0;
  z-index: 1;
}

table {
  border-collapse: collapse;
  width: 100%;
}
th,
td {
  padding: 8px 16px;
}
th {
  background: #eee;
}
<div>
  <h1>EMPLOYEE DATA FOR MAY 2023</h1>
</div>
<div class="tableFixHead">
  <table>
    <thead>
      <tr><th>SR.NO</th><th>EMPLOYEE</th></tr>
    </thead>
    <tbody>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
      <tr><td>1</td><td>Hritik</td></tr>
      <tr><td>2</td><td>Jay</td></tr>
      <tr><td>3</td><td>Rohit</td></tr>
      <tr><td>4</td><td>Nishant</td></tr>
      <tr><td>5</td><td>Mayur</td></tr>
    </tbody>
  </table>
</div>
mr.Hritik
  • 577
  • 3
  • 19
1

In the snippet below, the HTML and CSS part are resolving the scrollability of tbody, whereas, for the purpose of filling the gap between the upper content and the lower and of the screen, I applied Javascript.

function adjustTable() {
    let foo = document.getElementById('foo');
    let fooBody = foo.querySelector('tbody');
    fooBody.style.height = 0.9 * (window.innerHeight - fooBody.getBoundingClientRect().top) + "px";
}

window.addEventListener('load', adjustTable);

window.addEventListener('resize', adjustTable);
thead, tbody {
    display: block;
}

tbody {
    overflow-y: auto;
}
<div>
      top content
    </div>
    <table id="foo">
      <thead>
        <tr><th>... first header row</th></tr>
        <tr><th>... second header row</th></tr>
      </thead>
      <tbody>
        <tr><td>1</td></tr>
        <tr><td>2</td></tr>
        <tr><td>3</td></tr>
        <tr><td>4</td></tr>
        <tr><td>5</td></tr>
        <tr><td>6</td></tr>
        <tr><td>7</td></tr>
        <tr><td>8</td></tr>
        <tr><td>9</td></tr>
        <tr><td>10</td></tr>
        <tr><td>11</td></tr>
        <tr><td>12</td></tr>
        <tr><td>13</td></tr>
        <tr><td>14</td></tr>
        <tr><td>15</td></tr>
        <tr><td>16</td></tr>
        <tr><td>17</td></tr>
        <tr><td>18</td></tr>
        <tr><td>19</td></tr>
        <tr><td>20</td></tr>
        <tr><td>21</td></tr>
        <tr><td>22</td></tr>
        <tr><td>23</td></tr>
        <tr><td>24</td></tr>
        <tr><td>25</td></tr>
        <tr><td>26</td></tr>
        <tr><td>27</td></tr>
        <tr><td>28</td></tr>
        <tr><td>29</td></tr>
      </tbody>
    </table>

EDIT

As per the comment section, I was asked to edit this answer and add an adjustment for window resize as well as upper content change. I have updated the snippet above to handle resize event as well accordingly. As about handling upper content changes, a mutation observer can be used for that purpose in worst case scenarios, but if you have additional information about the upper content, then you can add handlers for it.

If we are to go with a mutation observer, then we can just call adjustTable() when dom changes are detected.

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
  • So far this is the best answer. It works nice and is not complicate. Please, add adjustments in case of window resize and change of top content. – Zoran May 03 '23 at 21:02
  • @Zoran thanks for the observation. I have added a handler for window resize. As for upper content change, I have shared a link to another SO discussion about mutation observers. If you do not have further information about your actual upper content, then you can apply the mutation observer idea described by vsync in the linked page (I have used that idea in my projects). But, if you have further information about the upper content, for instance, then you might have an easier solution. – Lajos Arpad May 03 '23 at 21:33
0

You can use CSS.

.mytable tbody{
  display:block;
  overflow:auto;
  height:50px; /* set table height here */
  width:100%; 
}
.mytable thead tr{
  display:block;
}
<div>
    top content
</div>
<table class="mytable">
    <thead>
        <tr>
            <th>thead td 1</th>
            <th>thead td 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>
    <tr>
      <td>cell 1</td>
      <td>cell 2</td>
    </tr>
    <tr>
      <td>cell 1</td>
      <td>cell 2</td>
    </tr>
    </tbody>
</table>
msmer
  • 129
  • 4
  • Dear msmer, your solution works nice, but has limitation of fixed height of tbody. Is there some way to style tbody to occupy rest of available viewport? – Zoran May 03 '23 at 13:00