How to Make a Table Row Sticky
Last updated: October 21, 2024
I needed to pin a summary row at the bottom of a scrollable data table, the kind where you have hundreds of rows and the totals row should always be visible. Came up while building a real-time options table with lots of scrolling.
The approach
The basic idea is position: sticky on a <tr> or <tfoot> with bottom: 0. This pins the row to the bottom of the scroll container.
}
For header pinning, same idea but top: 0 on <thead>.
The tricky part is that position: sticky on table elements requires the table (or its container) to be the scroll container. If the page itself scrolls instead of the table, the sticky row sticks to the viewport, not what you want. Wrap the table in a div with overflow-y: auto and a fixed height.
For row pinning mid-table (not header/footer), libraries like Material React Table handle it by absolutely positioning pinned rows. The Cushion App approach is simpler: just sticky footers.
Mobile gotchas
position: sticky breaks on some mobile browsers. Common causes:
overflow: hiddenon any ancestor kills sticky behavior. The element needs an actual scroll container up the chain-webkit-overflow-scrolling: touchon iOS can interfere- Some Android browsers don't support sticky on
<tr>elements, so you may need to apply it to each<td>in the row instead
Relevant threads: SO #1, SO #2
References
- CSS-Tricks: Making Tables with Sticky Header and Footers
- MDN: Element.scrollIntoView() — alternative approach: scroll the target row into view programmatically
- Material React Table: Row Pinning