Fix InitialItemIndex viewport underfill for small items in big container - #67936
Open
ilonatommy wants to merge 14 commits into
Open
Fix InitialItemIndex viewport underfill for small items in big container#67936ilonatommy wants to merge 14 commits into
ilonatommy wants to merge 14 commits into
Conversation
ilonatommy
temporarily deployed
to
copilot-pat-pool
July 21, 2026 12:21 — with
GitHub Actions
Inactive
ilonatommy
temporarily deployed
to
copilot-pat-pool
July 21, 2026 12:21 — with
GitHub Actions
Inactive
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a Blazor Virtualize/QuickGrid startup issue where small InitialItemIndex values could leave the viewport bottom underfilled until the user scrolls. It does this by deferring “leading overscan” (items reserved above the target) until the component has received its first spacer/measurement feedback, and adds E2E coverage to prevent regressions.
Changes:
- Add a
_hasSpacerFeedbackflag to detect when initial spacer observer feedback has occurred and use it to avoid reserving pre-target overscan during the initial unmeasured window seed. - Mark spacer feedback as received when
OnBeforeSpacerVisible/OnAfterSpacerVisiblerun, restoring the normal overscan-before-target behavior after measurement. - Add E2E tests asserting that both
QuickGridandVirtualizefill the viewport for smallInitialItemIndexvalues (including a small overscan scenario), plus minor test-asset updates to support the scenario.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/Components/Web/src/Virtualization/Virtualize.cs | Defers leading overscan until spacer feedback exists to prevent initial viewport underfill. |
| src/Components/test/testassets/BasicTestApp/VirtualizationAnchorMode.razor | Adds a UI toggle to set a small overscan to reproduce/validate the scenario. |
| src/Components/test/testassets/BasicTestApp/QuickGridTest/QuickGridScrollComponent.razor | Adjusts rendered item styling in the scroll/initial-index test component used by E2E coverage. |
| src/Components/test/E2ETest/Tests/VirtualizationTest.cs | Adds E2E assertions ensuring initial-index loads cover the viewport bottom with real items for both QuickGrid and Virtualize. |
… same top-of-list logic.
bottom. There are no rows below to load and re-running distribution unpinned the scroller from the bottom.
Open
3 tasks
…he loop kept re-pinning the original target and fought the user's scroll, dragging the viewport away. Stop new callbacks when user scrolls.
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.
Fixes #67933
Problem
Loading a
Virtualize(orQuickGrid) at a smallInitialItemIndexe.g. 10 rendered only a few rows below the target and left a blank gap at the bottom of the viewport, with no items and no placeholders. The gap only filled once the user manually scrolled. Best visible in bigger containers with smaller than average items.Example: a 300px container with fixed 50px rows fits 6 rows.
InitialItemIndex=10rendered only items 10–13, leaving room for 14 and 15 empty.Root cause
InitialItemIndexaligns the target row to the top of the viewport.On a fresh load, before any spacer-observer measurement has arrived,
MoveWindowToContainonly has a minimal seed capacity (OverscanCount * 2 + 1). It still reservedOverscanCountrows before the target. Because the target is top-aligned, those leading rows land off-screen (above). The small seed window no longer has enough rows to cover the area below the target. The shorter the final rendered items and the bigger the viewport, the more the issue is visible. From this reason regression tests are growing the container 300px->900px.• QuickGrid (default
OverscanCount = 3) -> seed of 7 rows, 3 wasted above -> underfills.• Pure Virtualize (
OverscanCount = 15) -> seed of 31 rows, big enough to mask the issue in most cases.The window would only correct itself via a spacer-observer callback, which is suppressed during a programmatic scroll.
Fix
The goal was to make the
InitialIndexItemlogic more similar to 0-th item loading logic that never has issues with filling in the viewport because it doesn't suppress callbacks. To achieve it, we releaseOnSpacerBeforeVisiblecallbacks until the viewport is filled so that C# fills the rows below the target, covering the whole viewport immediately, without user manual scrolls. It basically acts like the user scroll but keeping thescrollToppinned to the target position.