20

I'm setting up a website using Gatsby 2.2.10 and the Link components are retaining the scroll positions of the previous page and not scrolling back to the top when they're clicked.

<div className="Footer__legal body">
 <p>© {new Date().getFullYear()} My Nice Company</p>
 <Link to="/privacy-policy">Privacy Policy</Link>
 <Link to="/page-2">Page 2 Link component</Link>
</div>

Expected behaviour:

When you click 'Privacy Policy', 'Page 2' or any page at the bottom of the website, I expect the page to load with user being back at the top.

Actual Behaviour:

User stays at scroll position of the current page

Jack David Evans
  • 343
  • 1
  • 2
  • 11

10 Answers10

9

You can also modify gatsby-browser.js and implement a hook for each scroll update:

// in gastby-browser.js
exports.shouldUpdateScroll = ({
  routerProps: { location },
  getSavedScrollPosition,
}) => {
  const { pathname } = location
  // list of routes for the scroll-to-top-hook
  const scrollToTopRoutes = [`/privacy-policy`, `/page-2`]
  // if the new route is part of the list above, scroll to top (0, 0)
  if (scrollToTopRoutes.indexOf(pathname) !== -1) {
    window.scrollTo(0, 0)
  }

  return false
}

You will find the code for shouldUpdateScroll on GitHub or in the documentation for shouldUpdateScroll on the GatsbyJS website.

Michael W. Czechowski
  • 3,366
  • 2
  • 23
  • 50
  • Did this work for you? I'm not having any luck. Any Link I open takes me to the new route scrolled down the same as I was on the previous page. – jj0b Nov 26 '19 at 01:57
  • @jj0b Did you restart your gatsby command? Changes in `gatsby-config.js` and `gatsby-browser.js` etc. are effective after restarting your develope/serve/build process. – Michael W. Czechowski Nov 27 '19 at 10:40
  • I did. The thing that finally worked for me was using document.getElementById("WhateverIdYouWantToScrollTo").scrollIntoView() instead of window.scrollTo(0,0). I happened to use it in a useEffect hook but I'm sure any of the other ways of triggering that line a the right time would likely have worked for me. More details here: https://stackoverflow.com/questions/33188994/scroll-to-the-top-of-the-page-after-render-in-react-js/59079771#59079771 – jj0b Nov 28 '19 at 18:59
  • 1
    This worked, I just put the `window.scrollTo()` without condition as I wanted to have it on all page navigations. – Kevin Van Ryckegem Nov 29 '20 at 00:35
  • Thank you, this finally fixed my scroll issue with Gatstby v4.13.1 – C-Dev Sep 27 '22 at 20:07
  • thanks this worked, in firefox but not worked on chrome must spam refresh – Nandawaan Libya Mar 28 '23 at 17:16
9

If you have overflow: hidden or overflow: auto set on body, you'll have this issue!

SherylHohman
  • 16,580
  • 17
  • 88
  • 94
Addison
  • 149
  • 1
  • 2
  • Welcome, and Thanks for your contribution. Please consider updating your post with an ` edit` to explain why this happens, or a link to documentation indicating that this is the defined/expected behavior. – SherylHohman Apr 08 '20 at 20:28
  • This actually was the fix for me–I had overflow: auto on my body. I'm not sure why this is the case, but hopefully someone can help explain why. – Hunter Becton Apr 22 '20 at 16:33
5

If your page is a functional component, you can use the useEffect hook to scroll back to the top of the page, assuming that you are using graphql and so your component takes some data as an argument. This way every time that data changes, you scroll to the top of the page(works similar to componentDidUpdate).

const PageCmp = ({ data }) => {
    ...
    useEffect(() => {
        window.scrollTo(0,0)
    }, [data])
    ...
}
Sam
  • 1,765
  • 11
  • 82
  • 176
4

useEffect(() => window.scrollTo(0, 0), []) solved the issue for me. I was having the problem only on firefox but not on chrome. Idk what was causing the issue but it works fine now.

KMA Badshah
  • 895
  • 8
  • 16
2

Ok, this is an old question, but I've recently faced the same odd behavior. Turns out my problem was different from all other solutions I've seen in the internet so far.

Gatsby uses a package called gatsby-react-router-scroll. This package manages Gatsby's scroll behavior. This behavior is mainly implemented in Scroll Handler component. This component only scrolls up in componentDidUpdate method, and not in the componentDidMount one. I've added a debugger in the componentDidMount method and ScrollHandler component was being re-mounted at each navigation.

The fix was to figure out why this component was being mounted and remounted at each navigation. In my case, I had a React.StrictMode component on wrapRootElement function in my gatsby-browser.js. Removing StrictMode made ScrollHandler component stable, thus solving my problem.

  • +1 for the explanation. But [KMA Badshah's answer](https://stackoverflow.com/a/64446807/8087608) did the trick for me. Wished you added some code snippets. – Peter Umoren Jul 24 '23 at 14:32
1

Figured out a workaround by converting index.js page into a class-based component and then added

  componentDidUpdate() {
    window.scrollTo(0,0);
  }

Not the cleanest fix nor do I know why it wasn't scrolling automatically, going to a JS meet up next week so will ask the question then and post a follow up if I get an answer.

I have a feeling it's something to do with my styles, as I started a new project and the Gatsby-cli had no issues. Will be refactoring styles to see if this fixes the issue.

Note: Returning to this following Michael's answer, it also related to an overflow: hidden; style I had on the body, removing this also fixed my issue.

Jack David Evans
  • 343
  • 1
  • 2
  • 11
  • 2
    Returning to this following Michael's answer above, it also related to an `overflow: hidden;` style I had on the body, removing this also fixed my issue. – Jack David Evans Oct 02 '19 at 15:38
  • I am glad, that I could have helped. I'd like to mention one little thing: Instead of adding a comment, think about editing your answer and adding something like "**Note: ...**" – Michael W. Czechowski Oct 04 '19 at 08:10
  • 1
    @JackDavidEvans - I was having this problem and I did have a overflow: hidden on my body! removing that solved this for me! Thank you so much! – Chenzo Feb 21 '20 at 21:57
1

My problem was that I had html {height: 100%}. Removing that rule seemed to have solved the problem.

I also have gatsby-plugin-transition-link in my project, which has added more wrappers around my main content.

Jay
  • 368
  • 1
  • 3
  • 14
1

In my CSS, I had

html, body {
  height: 100%;
  overflow-y: scroll;
}

because it was the only way to fix a mobile-safari-only bug (my favorites!)

If you also can't get rid of overflow properties, I suggest this:

// in gatsby-browser.js
export function shouldUpdateScroll(prevRouterProps, { location }) {
  window.scrollTo(0, 0)
  const body = document.getElementsByTagName('body')[0]
  body.scrollTop = 0
  return false
}
Félix Paradis
  • 5,165
  • 6
  • 40
  • 49
1

I have a header set with position: fixed; and then a div with margin-top: 100px; so my content starts below the header (that has a 100px height). I had the scrolling issue until I changed margin to padding: padding-top: 100px;

loudo
  • 43
  • 1
  • 7
0

To further some of the answers above, I had to stick a time out in the useEffect to get it to work consistently. Seems to work with a timeout as little as 1ms.

useEffect(() => {
  let windowScrollTimeout = setTimeout(() => {
    window.scrollTo(0, 0)
    clearTimeout(windowScrollTimeout)
  }, 1)
}, [])
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
Folyik
  • 3
  • 5