fix(sessions): smooth conversation scroll-up jank#2960
Merged
richardsolomou merged 7 commits intoJun 28, 2026
Conversation
The transcript virtualizer seeded every row with a flat 80px estimate while real rows range from ~32px chips to 1000px diffs. A thread opens scrolled to the bottom, so only the last few rows ever get measured; the first scroll-up corrects every row above from estimate to true height at once, and tanstack skips scroll compensation during backward scroll, so the uncompensated growth shoves the viewport. Add a content-aware per-row estimate to shrink each correction, and compensate scrollTop for above-viewport resizes regardless of scroll direction so visible content stays put. Bottom-follow is unaffected. Generated-By: PostHog Code Task-Id: f1ca2a14-42ac-49de-8ccd-b1f2de1e10e0
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
Contributor
|
Reviews (1): Last reviewed commit: "fix(sessions): smooth conversation scrol..." | Re-trigger Greptile |
Profiling the scroll-up showed the jank comes from tall, async-rendered rows (long markdown with code blocks, diffs): with overscan 6 each one was first measured and painted as it entered the viewport, so its true height replaced the estimate (≈300px of accumulated shift) and its paint landed on the visible frame (≈140ms hitches, ~25% dropped frames). Rendering 12 rows ahead moves that work off the visible critical path — measured shift drops to 0, worst frame to ~56ms, dropped frames to ~5%. Also size edit-diff rows by their changed lines (the unified diff collapses unchanged context, so the old whole-file guess over-estimated) and reserve a diff's measured height across remounts so it can't collapse to zero while its highlight worker re-initializes. Generated-By: PostHog Code Task-Id: f1ca2a14-42ac-49de-8ccd-b1f2de1e10e0
…gnment Address review: cover every chip-style row arm with it.each (exact px), and assign the scroll-compensation predicate once via a ref guard instead of on every render. Keep it in render, not a mount effect, so it precedes the virtualizer's first measurement pass. Generated-By: PostHog Code Task-Id: f1ca2a14-42ac-49de-8ccd-b1f2de1e10e0
Contributor
|
Reviews (2): Last reviewed commit: "test(sessions): parameterize chip estima..." | Re-trigger Greptile |
Trim verbose comments to their load-bearing facts. Generated-By: PostHog Code Task-Id: f1ca2a14-42ac-49de-8ccd-b1f2de1e10e0
Contributor
|
thank you!! still reviewing but my gut doesn't love the estimated height values at first glance haha - what are the perf gains like with just the overscan adjustment? |
Profiling showed the deeper overscan (6→12) erases the scroll-up layout shift on its own — rows render and measure ahead of the viewport, so they enter view already sized and painted. The content-aware estimates, diff height-reservation, and scroll-compensation predicate were chasing the same jank before that landed and add nothing measurable on top, so drop them. Generated-By: PostHog Code Task-Id: f1ca2a14-42ac-49de-8ccd-b1f2de1e10e0
Member
Author
|
@adboio good catch, profiled it again with just the overscan bump, yeah its the one doing most of the work <3 |
adboio
approved these changes
Jun 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Scrolling up through a conversation was janky — heavy stutter and content jumping — past stretches of tall rows (long markdown messages with code blocks, and file-edit diffs). Scrolling down, or back up a second time over the same rows, was smooth.
Profiled over CDP: the cause is tall, expensive, async-rendered rows combined with a shallow overscan. With
overscan: 6, each such row was first rendered and measured as it entered the viewport, which does two bad things on the visible frame:Second pass was smooth because measured heights and syntax highlighting were already cached.
Changes
Deepen the overscan, 6 → 12. Rendering rows ~12 ahead moves the measure + paint work off the visible critical path: by the time a row scrolls into view it's already measured and painted. Measured before/after, same thread, same scroll:
That's the whole change. An earlier version of this PR also added content-aware row estimates, a diff height-reservation, and a scroll-compensation predicate; profiling showed the overscan bump erases the shift on its own and those added nothing measurable on top (overscan renders rows ahead, so they never enter view unmeasured), so they were dropped to keep the fix minimal.
How did you test this?
scrollHeightdeltas (numbers above). Also A/B'd overscan-12 with vs without the estimate machinery — identical 0px shift, confirming overscan is what matters.Automatic notifications
Created with PostHog Code