From e1da41ffdfd984f844c9528ead2d66fd83749aed Mon Sep 17 00:00:00 2001 From: Andrew Scott Date: Mon, 6 Oct 2025 11:28:49 -0700 Subject: [PATCH] fix(router): Scroll restoration should use instant scroll behavior for traversals (#64299) When the scroll position is being restored, this change upates the behavior to use 'instant' rather than the default 'auto', which will be whatever the browser behavior is for 'window.scrollTo'. The 'smooth' behavior does not match how browsers behavior when performing a traversal navigation for MPAs, which is 'instant'. related to #58258 PR Close #64299 --- packages/router/src/router_scroller.ts | 5 +++-- packages/router/test/router_scroller.spec.ts | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/router/src/router_scroller.ts b/packages/router/src/router_scroller.ts index 9e14bd0b357..739c0e39b54 100644 --- a/packages/router/src/router_scroller.ts +++ b/packages/router/src/router_scroller.ts @@ -85,12 +85,13 @@ export class RouterScroller implements OnDestroy { private consumeScrollEvents() { return this.transitions.events.subscribe((e) => { if (!(e instanceof Scroll)) return; + const instantScroll: ScrollOptions = {behavior: 'instant'}; // a popstate event. The pop state event will always ignore anchor scrolling. if (e.position) { if (this.options.scrollPositionRestoration === 'top') { - this.viewportScroller.scrollToPosition([0, 0]); + this.viewportScroller.scrollToPosition([0, 0], instantScroll); } else if (this.options.scrollPositionRestoration === 'enabled') { - this.viewportScroller.scrollToPosition(e.position); + this.viewportScroller.scrollToPosition(e.position, instantScroll); } // imperative navigation "forward" } else { diff --git a/packages/router/test/router_scroller.spec.ts b/packages/router/test/router_scroller.spec.ts index 0176037e3a2..90d0e7bd697 100644 --- a/packages/router/test/router_scroller.spec.ts +++ b/packages/router/test/router_scroller.spec.ts @@ -96,7 +96,9 @@ describe('RouterScroller', () => { events.next(new NavigationStart(3, '/a', 'popstate', {navigationId: 1})); events.next(new NavigationEnd(3, '/a', '/a')); await nextScrollEvent(events); - expect(viewportScroller.scrollToPosition).toHaveBeenCalledWith([10, 100]); + expect(viewportScroller.scrollToPosition).toHaveBeenCalledWith([10, 100], { + behavior: 'instant', + }); }); }); @@ -146,7 +148,7 @@ describe('RouterScroller', () => { events.next(new NavigationEnd(3, '/a#anchor', '/a#anchor')); await nextScrollEvent(events); expect(viewportScroller.scrollToAnchor).not.toHaveBeenCalled(); - expect(viewportScroller.scrollToPosition).toHaveBeenCalledWith([0, 0]); + expect(viewportScroller.scrollToPosition).toHaveBeenCalledWith([0, 0], {behavior: 'instant'}); }); });