JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.0/css/bootstrap.min.css">
<div>
<table class="table">
<thead>
<tr><th width="20%">Heading</th><th>Heading</th></tr>
</thead>
<tbody>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
</tbody>
</table>
</div>
<div>
<table class="table" data-stick-headers="false">
<thead>
<tr><th width="20%">Heading</th><th>Heading</th></tr>
</thead>
<tbody>
<tr><td>text</td><td>This table header will not stick becasue of data attr</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
<tr><td>text</td><td>text</td></tr>
...
CSS
.table-sticked {
margin:0 !important;
}
JavaScript
$(function() {
// Use the function
$(document).find("table").not('.table-nested, .table-sticked').stickTableHeaders();
});
// Function stickTableHeaders
jQuery.fn.stickTableHeaders = function() {
return this.each(function()
{
if(!$(this).is('[data-stick-headers="false"]') && !$(this).is('.table-sticked')) {
var table = $(this),
header = table.children('thead'),
sticked = $('<table></table>').addClass('table table-sticked').css({'margin':'0'}).append(header.clone());
// Manualy aply styles to the cloned thead and everything in it. Don't know if you'll need this?
sticked.find('th').css({'backgroundColor': '#fff'}).removeAttr('width');
$(window).resize(function() {
// Be sure it recalculates stuff on window resize
sticked.find('th').each(function() {
var headerTH = header.find('th').eq($(this).index());
if(headerTH.is('[width]') || headerTH.is(':first-child') || headerTH.is(':last-child')) {
$(this).width(header.find('th').eq($(this).index()).width());
}
else {
$(this).width(header.find('th').eq($(this).index()).width());
}
});
table.css({'marginTop':-header.height()});
}).trigger('resize');
// top property should be position where to stay sticky
sticked.css({'display':'table','width':'100%','position':'sticky','top':0, 'zIndex':'10'});
$(this).before(sticked);
}
});
};