-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Enhanced navigation should not scroll before content renders #64054
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes a visual timing bug in enhanced navigation where scroll resets occurred before new content rendered, causing a noticeable flash. The solution introduces a new ScrollResetSchedule enum to coordinate scroll timing with DOM updates.
Key changes:
- Enhanced navigation now defers scroll resets until after new DOM content is applied
- Added
ScrollResetScheduleenum to track different timing phases for scroll resets - Implemented scroll position tracking in E2E tests to verify the fix
Reviewed Changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| FormWithParentBindingContextTest.cs | Uses shared IsStale() extension method instead of local implementation |
| EnhancedNavigationTest.cs | Adds scroll timing regression tests with new observation utilities |
| WebDriverExtensions.cs | Introduces IsStale() extension and scroll observation infrastructure |
| ScrollOverrideScope.cs | New test utility that intercepts and logs window.scrollTo calls |
| NavigationManager.ts | Updates to use new scheduleScrollReset API with AfterBatch timing |
| NavigationEnhancement.ts | Schedules scroll resets for AfterDocumentUpdate instead of immediate execution |
| Renderer.ts | Implements ScrollResetSchedule enum and timing-based scroll reset logic |
| Boot.Web.ts | Triggers AfterDocumentUpdate scroll resets in the shared documentUpdated callback |
| shouldResetScrollAfterNextBatch = true; | ||
| } | ||
| export function scheduleScrollReset(timing: ScrollResetSchedule): void { | ||
| if (timing != ScrollResetSchedule.AfterBatch) { |
Copilot
AI
Oct 23, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use strict inequality operator !== instead of != for type-safe comparison.
| if (timing != ScrollResetSchedule.AfterBatch) { | |
| if (timing !== ScrollResetSchedule.AfterBatch) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. Only added a request for documentation.
| export enum ScrollResetSchedule { | ||
| None, | ||
| AfterBatch, | ||
| AfterDocumentUpdate, | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to add comments explaining the values? When someone comes to this a year later they might have harder time understanding the difference between AfterBatch and AfterDocumentUpdate.
Prevent visual flash during navigation
This is a timing bug, specially visible on browsers with slower connection or when the page intentionally delays rendering. Because enhanced page load fetches and applies the new DOM asynchronously, the immediate scroll-up run against the previous page's DOM. User sees a page A jump to the top and only after the fetch of new page is completed - the page B replaces it.
Description
ScrollResetSchedule.AfterDocumentUpdate, removing the flash that occurred while the old DOM was still visible.Boot.WebinvokesresetScrollIfNeeded(ScrollResetSchedule.AfterDocumentUpdate)from the shareddocumentUpdatedcallback so every enhanced navigation (including streaming SSR) scrolls exactly once, right after new content arrives.ScrollResetScheduleenum and only callswindow.scrollTowhen the requested phase triggers, instead of scrolling immediately.NavigationManagerrequestsAfterBatchwhen client-side navigation changes pages, letting the render batch complete before the scroll reset.WebDriverExtensions.IsStalehelpers and the scroll observation utilities so we rely on a single stale-element check and avoid copy/pasted extension method logic.Fixes #64015