Hi, we found what looks like a bad fit between applyScrollAdjustment and a streaming chat UI.
We’re using @tanstack/vue-virtual for a chat window with dynamically growing assistant messages.
The problem is:
- if a streaming message is visible and keeps getting taller
- the virtualizer keeps adjusting
scrollTop
- so the viewport slowly moves downward by itself
This is not "scroll to bottom".
It is more like "keep the same relative distance / keep the same visual anchor", but in a streaming chat this feels wrong.
What we expect in this scenario is:
- if the user is not manually scrolling
- and a visible streaming message grows in place
- the viewport should stay where it is
In our case, not adjusting scroll is stable.
Adjusting scroll is what creates the bad experience, because the viewport gets dragged down continuously as the message grows.
What we observed
We traced the call chain and confirmed the movement comes from virtualizer size correction:
ResizeObserver -> resizeItem -> applyScrollAdjustment -> _scrollToOffset -> scrollToFn
So this is not our own "scroll to bottom" logic.
It is the internal scroll correction path.
Repro shape
The behavior is easiest to see when:
- the viewport is currently looking at the streaming message itself
- especially when there is little or no stable content above it in the viewport
- the message keeps growing during streaming
Then scrollTop keeps increasing together with scrollHeight, and the distance from bottom stays roughly constant.
Example of what happens:
- before growth:
scrollTop = 900, distanceToBottom = 100
- after growth:
scrollTop = 1000, distanceToBottom = 100
From the user’s point of view, the page is moving by itself.
Why this feels wrong in chat streaming
I understand the goal of scroll correction is to prevent visible jumping when item sizes change.
But for a streaming chat message that is already on screen, this correction does the opposite: it creates visible motion that would not exist if scroll stayed untouched.
So for this case, "do not correct" is actually the more stable result.
Our workaround
We currently override scrollToFn and block only virtualizer scroll corrections during streaming.
In practice, we detect the internal correction by checking adjustments !== 0, and while chat streaming is active we skip that scroll request.
Very roughly:
function scrollToFn(offset, { adjustments, behavior }, instance) {
if (chatStreamingActive && adjustments !== 0) {
return
}
instance.scrollElement?.scrollTo({
top: offset,
behavior: behavior ?? 'auto',
})
}
This has been working much better for us because:
- manual scrolling still works
- explicit "scroll to bottom" still works
- but the viewport is no longer dragged downward by streaming height growth
Question
Is this expected behavior for applyScrollAdjustment?
And more importantly, would it make sense to support a first-class option for this use case, something like:
- disable correction for visible item growth
- disable correction during streaming / live updates
- or make the correction strategy more controllable for chat UIs
Right now the internal correction seems correct for many list cases, but not for this streaming chat case.
If useful, I can also provide a minimal reproduction.
Hi, we found what looks like a bad fit between
applyScrollAdjustmentand a streaming chat UI.We’re using
@tanstack/vue-virtualfor a chat window with dynamically growing assistant messages.The problem is:
scrollTopThis is not "scroll to bottom".
It is more like "keep the same relative distance / keep the same visual anchor", but in a streaming chat this feels wrong.
What we expect in this scenario is:
In our case, not adjusting scroll is stable.
Adjusting scroll is what creates the bad experience, because the viewport gets dragged down continuously as the message grows.
What we observed
We traced the call chain and confirmed the movement comes from virtualizer size correction:
ResizeObserver -> resizeItem -> applyScrollAdjustment -> _scrollToOffset -> scrollToFnSo this is not our own "scroll to bottom" logic.
It is the internal scroll correction path.
Repro shape
The behavior is easiest to see when:
Then
scrollTopkeeps increasing together withscrollHeight, and the distance from bottom stays roughly constant.Example of what happens:
scrollTop = 900,distanceToBottom = 100scrollTop = 1000,distanceToBottom = 100From the user’s point of view, the page is moving by itself.
Why this feels wrong in chat streaming
I understand the goal of scroll correction is to prevent visible jumping when item sizes change.
But for a streaming chat message that is already on screen, this correction does the opposite: it creates visible motion that would not exist if scroll stayed untouched.
So for this case, "do not correct" is actually the more stable result.
Our workaround
We currently override
scrollToFnand block only virtualizer scroll corrections during streaming.In practice, we detect the internal correction by checking
adjustments !== 0, and while chat streaming is active we skip that scroll request.Very roughly:
This has been working much better for us because:
Question
Is this expected behavior for
applyScrollAdjustment?And more importantly, would it make sense to support a first-class option for this use case, something like:
Right now the internal correction seems correct for many list cases, but not for this streaming chat case.
If useful, I can also provide a minimal reproduction.