Mooseman
Mooseman

Reputation: 18891

Responsive Bootstrap Table with Sticky Header

I have a table. The only CSS I am adding to the standard Bootstrap library is the following to implement the sticky header:

.table-sticky th {
  background: #fff;
  position: sticky;
  top: -1px;
  z-index: 990;
}
<div class="table-responsive p-0 mt-2">
  <table class="table table-sm table-striped table-hover table-sticky">
    <thead>
      <tr>
        <th>#</th>
        <th>Header</th>
        <th>Header</th>
        <th>Header</th>
        <th>Header</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1,001</td>
        <td>Lorem</td>
        <td>ipsum</td>
        <td>dolor</td>
        <td>sit</td>
      </tr>
      <tr>
        <td>1,002</td>
        <td>amet</td>
        <td>consectetur</td>
        <td>adipiscing</td>
        <td>elit</td>
      </tr>
    </tbody>
  </table>
</div>

The sticky header worked until I wrapped the table in the div.table-responsive. How do I allow these to co-exist?

Upvotes: 8

Views: 6610

Answers (3)

michal.jakubeczy
michal.jakubeczy

Reputation: 9517

In this case you need to code it yourself. Following JS will do the job:

var element = document.getElementById("fixed-thead");
var parentElement = element.parentElement;
window.addEventListener('scroll', () => {
    var coordinates = parentElement.getBoundingClientRect();
    if (coordinates.y < 0) {
        element.style.transform = 'translate3d(0, ' + (-coordinates.y) + 'px, 0)';
    } else {
        element.style.transform = 'translate3d(0,0,0)';
    }
});

And in your table mark thead with id="fixed-thead" like this:

<thead id="fixed-thead">

I use translate3d to enable hardware acceleration to make it smoother. If user uses wheel to scroll scroll event is triggering very ofter I recommend using debouncing of scroll events.

In case your table has column with fixed with you can use setting position: fixed and top: 0 instead of translate3d. But in case of a variable length translate3d is preferred.

In case you need to apply this code to multiple pages on page use following code:

function applyFixedHeader(element) {
var parentElement = element.parentElement;
    window.addEventListener('scroll', () => {
        var coordinates = parentElement.getBoundingClientRect();
        if (coordinates.y < 0) {
            element.style.transform = 'translate3d(0, ' + (-coordinates.y) + 'px, 0)';
        } else {
            element.style.transform = 'translate3d(0,0,0)';
        }
    });
}

var elements = document.querySelectorAll("{yourSelector, e.g. `.table-fixed` for the tables containing class `table-fixed`}");
elements.forEach(element => applyFixedHeader(element));

Upvotes: 6

Salim Hamidi
Salim Hamidi

Reputation: 21411

without any additionnal CSS, you can fix table head by removing table-responsive from the div and adding class="bg-white sticky-top border-bottom" class to table tag. Like this

<div class="table">
  <table class="table">
   <thead>
    <tr>
     <th class="bg-white sticky-top border-bottom">FirstName</th>
     <th class="bg-white sticky-top border-bottom">LastName</th>
     <th class="bg-white sticky-top border-bottom">Class</th>
    </tr>
   </thead>
   <tbody>
     <tr>
       <td>John</td>
       <td>Cooker</td>
       <td>A1</td>
     </tr>
     <tr>
       <td>David</td>
       <td>Jeferson</td>
       <td>A2</td>
     </tr>
     ...
  </table>
</div>

Upvotes: 3

Mooseman
Mooseman

Reputation: 18891

There's no way to co-exist a position: sticky inside a .table-responsive without re-implementing the latter.

My solution ended up to be using .table-responsive-sm to refuse this trade-off when a responsive table is certainly not needed.

Upvotes: 10

Related Questions