Scroll restoration no longer works on popState when using shouldUpdateScroll browser API to orchestrate page transitions
See original GitHub issueDescription
At some point in the last six months or so the shouldUpdateScroll browser API hook and related functionality seems to have been changed under the hood and introduced breaking changes to scroll restoration for Gatsby sites that use a simple animated page transition implementation (as introduced by @ryanwiemer: https://github.com/ryanwiemer/gatsby-using-page-transitions).
I’d guess there could be a significant number of sites affected considering the many themes and starters that make use of this page transition technique.
Here’s the bit of code that gets added to gatsby-browser.js to support scroll restoration with animated page transitions (which rely on gatsby-plugin-layout and your animation library of choice):
const transitionDelay = 600;
export const shouldUpdateScroll = ({
routerProps: { location },
getSavedScrollPosition
}) => {
if (location.action === "PUSH") {
window.setTimeout(() => window.scrollTo(0, 0), transitionDelay);
} else {
const savedPosition = getSavedScrollPosition(location);
window.setTimeout(
() => window.scrollTo(...(savedPosition || [0, 0])),
transitionDelay
);
}
return false;
};
Essentially, scroll restoration no longer works correctly on popState when page transitions are involved.
Console logging the savedPosition
that gets retrieved in the code snippet above always returns 0. There are two issues here:
- The function is returning a single number rather than an
[x, y]
coordinate array as expected per the documentation here: https://www.gatsbyjs.com/docs/browser-apis/#shouldUpdateScroll - The function always returns 0 despite the scroll position saved in session storage, so even when modifying the code above to
window.scrollTo(0, savedPosition || 0)
, the user is always sent to the top of the page when using browser back or forward buttons.
Steps to reproduce
On the demo link below, scroll all the way to the bottom of the index page, click the link to Page 2, and then click the browser back button. You will land back at the top of the index page rather than where you left off at the bottom.
Demo link: https://gatsby-scroll-restoration-issue.netlify.app/ Demo repo: https://github.com/blimpmason/gatsby-scroll-restoration-issue
Expected result
On the comparison demo link below (which uses an older version of Gatsby, v2.19.43, along with matching dependency versions), scroll all the way to the bottom of the index page, click the link to Page 2, and then click the browser back button. You should always land you exactly where you were at the bottom of the index page.
Demo link (working comparison): https://gatsby-scroll-restoration-issue-comparison.netlify.app/ Demo repo (working comparison): https://github.com/blimpmason/gatsby-scroll-restoration-issue-comparison
Actual result
You always end up back at the top of the page.
Environment
System:
OS: macOS 10.15.6
CPU: (8) x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 14.4.0 - ~/.nvm/versions/node/v14.4.0/bin/node
Yarn: 1.22.4 - /usr/local/bin/yarn
npm: 6.14.5 - ~/.nvm/versions/node/v14.4.0/bin/npm
Languages:
Python: 2.7.16 - /usr/bin/python
Browsers:
Chrome: 85.0.4183.121
Firefox: 81.0
Safari: 14.0
npmPackages:
gatsby: ^2.24.72 => 2.24.72
gatsby-image: ^2.4.20 => 2.4.20
gatsby-plugin-layout: ^1.3.13 => 1.3.13
gatsby-plugin-manifest: ^2.4.33 => 2.4.33
gatsby-plugin-offline: ^3.2.30 => 3.2.30
gatsby-plugin-react-helmet: ^3.3.12 => 3.3.12
gatsby-plugin-sharp: ^2.6.38 => 2.6.38
gatsby-source-filesystem: ^2.3.32 => 2.3.32
gatsby-transformer-sharp: ^2.5.16 => 2.5.16
npmGlobalPackages:
gatsby-cli: 2.12.80
Hi to @wardpeet and @blainekasten who may have seen my misplaced comments on this issue in a merged PR thread!
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:8 (4 by maintainers)
Top GitHub Comments
Thank you for opening this @blimpmason
And big kudos for the excellent reproduction! ❤️
I’ve bisected it and seems that it was introduced in
gatsby@2.21.15
: compare.The only suspicious PR is this one: #21626 and it is marked as a breaking change (but for the plugin not for gatsby). So this interesting.
I didn’t have a chance yet to see what we can do here, so if someone is ready to tackle this - we are happy to accept a PR with a fix!
Thanks @vrabe and @vladar! I just updated to gastby@2.29.0-next.1 to test the fix and it looks like the scroll coordinates are now coming back as an array as expected so scroll position can be used once again without modifying the gatsby-browser shouldUpdateScroll function.
Unfortunately I’m still experiencing an issue in which the page scrolls to the restored position before the setTimeout has completed — it seems the router is ignoring the shouldUpdateScroll logic.
Example here: https://fix-test--gatsby-scroll-restoration-issue.netlify.app/. You can see the issue when you scroll to the bottom of page 1, click the link to page 2 and then hit the browser back button.
I will open a new issue to address this issue.