I’m working on a project where I’m dynamically creating a large table using JavaScript and Tailwind CSS. I need certain headers and columns to stay “sticky” while scrolling horizontally and vertically. However, I’m facing an issue:
When I wrap the table in a div with the overflow-auto class, the position: sticky property stops working for the headers and columns. If I remove the overflow-auto class, the sticky positioning works correctly, but I lose the scrollbars, which are necessary because of the table’s size.
Here’s my code:
<div class="bg-white border-t border-gray-200 overflow-auto">
<table id="graph" class="w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr class="divide-x" id="table1-months-headers">
<th class="sticky top-0 left-0 z-50 bg-gray-50"></th>
<th class="sticky top-0 left-[50px] z-50 bg-gray-50"></th>
</tr>
<tr class="divide-x" id="table2-headers">
<th scope="col" class="sticky top-[40px] left-0 z-50 bg-gray-50 border-t border-gray-200 px-2 text-center whitespace-nowrap">
<span class="text-xs font-semibold uppercase tracking-wide text-gray-800">ID</span>
</th>
<th scope="col" id="name" class="sticky top-[40px] left-[50px] z-50 min-w-[200px] bg-gray-50 border-t border-gray-200 px-2 text-start whitespace-nowrap">
<div class="flex items-center gap-1">
<span class="text-xs font-semibold uppercase tracking-wide text-gray-800">Name</span>
</div>
</th>
<!-- Other headers -->
</tr>
</thead>
<tbody>
<!-- Dynamically generated table rows -->
</tbody>
</table>
</div>
I’m generating table headers and cells dynamically. Here’s how I’m adding the headers:
const monthsHeaders = $('#table1-months-headers');
let tdHeaders = `
<td class="px-2 text-center whitespace-nowrap bg-gray-50 border-b border-gray-200">
<span class="text-xs font-semibold uppercase tracking-wide text-gray-800">Total</span>
</td>
`;
monthsHeaders.append(tdHeaders);
months.forEach(month => {
let td = `<td class="sticky top-0 z-20 px-6 py-2 text-center whitespace-nowrap bg-gray-50 border-b border-gray-200" colspan="${month.days}">
<span class="upper-month text-xs font-semibold uppercase tracking-wide text-gray-800">${month.name}</span>
</td>`;
monthsHeaders.append(td);
});
const tableHeaders = $('#table2-headers');
tableHeaders.append(tdHeaders);
months.forEach(month => {
for (let i = 1; i <= month.days; i++) {
let th = `<th scope="col" class="sticky top-[40px] z-30 min-w-8 max-w-12 whitespace-nowrap bg-gray-50" data-date="${year}-${month.code}-${String(i).padStart(2, '0')}">
<span class="text-xs font-semibold uppercase tracking-wide">${i}</span>
</th>`;
tableHeaders.append(th);
}
});
What I’ve tried so far:
Parent container adjustments: Ensured correct position properties (relative, static, etc.) on parent elements.
Changing overflow properties: Tried various combinations of overflow properties on parent elements, like overflow-x, overflow-y, but the issue persists.
Restructuring HTML: Tried different HTML structures to see if a different hierarchy would help, but no luck.