Skip to content

fix: grid header bleeds through rows on scroll (#214)#229

Merged
EVWorth merged 1 commit into
mainfrom
fix/214-grid-header-bleed
Jul 20, 2026
Merged

fix: grid header bleeds through rows on scroll (#214)#229
EVWorth merged 1 commit into
mainfrom
fix/214-grid-header-bleed

Conversation

@EVWorth

@EVWorth EVWorth commented Jul 19, 2026

Copy link
Copy Markdown
Owner

What

Fixes the results grid header row leaking data text through itself during vertical scroll. Header now occludes row content as expected.

Why

Chromium / WebKit silently ignore position: sticky on <thead> / <th> when the table has border-collapse: collapse. Compounded by the absence of a background on the <thead> element itself (only the <th> cells had one), so any gap between cells showed row text peeking through. Visible in most scrolling sessions with anything more than a single-screen result set.

Changes

src/components/grid/ResultsGrid.tsx — 4 class-name edits, 0 logic changes:

Spot Change Why
<table> (line 750) border-collapseborder-separate border-spacing-0 Adjacent borders still touch but position: sticky works in Chromium + WebKit
<thead> (line 751) add bg-[var(--color-bg-tertiary)] Whole strip opaque (not relying on per-cell bg which could leave hairline gaps)
Virtualized header wrapper (line 597) add same bg Parity for shouldVirtualize branch (>5000-row results)
Scroll container <div> (line 591) add isolate z-0 Establishes a new stacking context so sticky cannot be painted under a sibling

Verification

Gate Result
npx vitest run src/components/grid/__tests__ 5 files / 101 tests pass
npx vitest run (full) 77 files / 1453 tests pass
npm run type-check 0 errors
npx eslint src/components/grid/ResultsGrid.tsx 0 errors (1 pre-existing warning, unrelated to this change)
npx dprint check clean
Lefthook pre-commit (all 7 commands) all green, no --no-verify needed

Why no new tests

The failure mode is a CSS rendering quirk in Chromium / WebKit. jsdom doesn't actually paint, so a class-presence assertion would only verify the markup change — not the visual outcome. The existing ResultsGrid.browser.test.tsx covers scroll behavior at the integration level; per the issue body, no test changes were specified.

Chromium/WebKit silently ignores `position: sticky` on <thead>/<th>
when the table has `border-collapse: collapse`. Compounded by
no background on <thead> itself (only <th> cells have one), so any
gap shows row text bleeding through.

Fix in src/components/grid/ResultsGrid.tsx:

1. `border-collapse` -> `border-separate border-spacing-0`.
   Visually identical (cell-adjacent borders still touch), but makes
   sticky work in Chromium + WebKit.

2. `bg-[var(--color-bg-tertiary)]` on <thead> so the whole strip
   is opaque rather than relying on individual <th> backgrounds.
   Keep <th> bg classes so hover-state layering still works.

3. Same bg applied to the virtualized-path header wrapper
   (`shouldVirtualize ? ...`) for parity (>5000-row results).

4. Scroll container gets `isolate z-0`. Establishes a stacking
   context so sticky cannot be painted under a sibling stacking
   context.

No tests added: the failing condition is a CSS rendering quirk in
Chromium/WebKit that jsdom does not reproduce, so a class-presence
assertion would be tautological. Browser tests cover scroll behavior
in ResultsGrid.browser.test.tsx.

Closes #214.
@EVWorth
EVWorth merged commit ffc319d into main Jul 20, 2026
10 checks passed
@EVWorth
EVWorth deleted the fix/214-grid-header-bleed branch July 20, 2026 00:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant