Fix: Transparent Header Cells on Horizontal Scroll with TanStack Table + TanStack Virtual

Just a guy who loves to write code and watch anime.
Search for a command to run...

Just a guy who loves to write code and watch anime.
No comments yet. Be the first to comment.
Qualities that make outstanding builders.

Bipedal vs quadrupedal: how many legs This is about the number of legs the creature walks on. Bipedal. Two legs. Humans, ostriches, T-rex, kangaroos, most fantasy humanoids. Quadrupedal. Four legs. Do

Intro You hear "lerp" and "smoothstep" everywhere in game dev. They sound like math jargon. They're not. Both are small tools that do the same job: smoothly move from one value to another. The problem

What is Kinematics Kinematics is the math field. It's the study of how things move without worrying about forces (which would be dynamics). FK and IK are the two branches: forward kinematics and inver

Intro Textures are usually the biggest cost in a 3D scene. Memory, bandwidth, and load time all get eaten by them. Resizing them is the obvious lever. There's more. This post is about the less obvious

When using TanStack Table with TanStack Virtual and many columns that extend beyond the viewport, scrolling horizontally causes the header cells to appear transparent. Body row content bleeds through behind the sticky header as you scroll right.
This happens even though the header row itself has bg-background.
In a typical virtualized data grid setup, the structure looks like this:
<div role="rowgroup" class="sticky top-0 z-10 grid"> <!-- header rowgroup -->
<div role="row" class="bg-background flex min-w-full"> <!-- header row -->
<div role="columnheader" class="relative shrink-0"> <!-- header cell (no bg!) -->
The header row has bg-background, but individual header cells only get bg-background conditionally — typically when header.column.getIsPinned() is true. Non-pinned header cells have no background.
When columns extend past the viewport width, the row's background doesn't fully cover all cells in certain rendering scenarios. The sticky positioning combined with min-w-full on the row and shrink-0 on cells creates a situation where the background doesn't paint behind overflow cells.
Two changes, both in the data grid component where headers are rendered:
bg-background to the header rowgroup <div
role="rowgroup"
data-slot="grid-header"
ref={headerRef}
- className="sticky top-0 z-10 grid"
+ className="bg-background sticky top-0 z-10 grid"
>
bg-background, not just pinned ones <div
role="columnheader"
- className={cn('relative shrink-0', {
+ className={cn('bg-background relative shrink-0', {
grow: stretchColumns && header.column.id !== 'select' && header.column.id !== 'actions',
- 'bg-background': header.column.getIsPinned(),
})}
>
The pinned-only conditional was the root cause. Every header cell needs an opaque background so nothing bleeds through when scrolling horizontally — not just the ones pinned to the left/right edge.