Aessandro
Aessandro

Reputation: 5761

Next.js link doesn't render with page scrolled at the top

I have a component like so:

const Milestone = props => {
  const { path, disabled, index, ...rest } = props;

  if (disabled) return <MilestoneCheck disabled />;

  return (
    <Link href={path} passHref>
      <a>
        <MilestoneCheck {...rest} />
      </a>
    </Link>
  );
};

when I click on the 'Link' to go to the next page and than click the back button to go back to where I came from, the page doesn't load at the top but from the last scrolled position. Adding a 'scrollTop' method on route change would feel not very efficient, is there a more elegant solution to always having the page loading at the top?

Upvotes: 18

Views: 30551

Answers (13)

Tim Kelly
Tim Kelly

Reputation: 1113

I'm using Next.js 13 with app router.

The fix for me was changing my wrapper element from:

<>
// your code
</>

to

<div>
</div>

Very annoying to find but this little fix worked for me.

Upvotes: 0

Mohammed Anas
Mohammed Anas

Reputation: 1

Change next configuration scrollRestoration to false.

experimental: { scrollRestoration: false }

Upvotes: 0

Marnix.hoh
Marnix.hoh

Reputation: 1912

Another reason pages are not scrolled to the top upon navigation is when the following style rule exists:

html { height: 100%; }

There is a Github issue on this here.

Upvotes: 3

Nikolai Kiselev
Nikolai Kiselev

Reputation: 6603

A possible cause could be overflow-x: hidden; on one of the root elements: body, html or #__next.

You can try to add min-height: 100% to it or replace it with overflow-x: clip;.

Upvotes: 6

Ardit Gashi
Ardit Gashi

Reputation: 1

This ended up working for me (updated to newest NextJS routing configuration)

Router.events.on('routeChangeComplete', (url) => {
      window.scroll({
        top: 0,
        left: 0,
      });
    });

Upvotes: 0

Diego
Diego

Reputation: 31

In my case I was using Bootstrap and I had to remove in the bootstrap.min.css file:

:root {
 scroll-behavior: 'smooth'
}

Upvotes: 3

Divine Hycenth
Divine Hycenth

Reputation: 660

I had this experience and I tried a lot of ways to get it to work but it didn't. This kind of route change behavior is supposed to happen by default except you're doing something different.

I noticed that after I removed overflow-x: hidden from my html/body tag everything started to work normally.

Try not to use this form of styling in your html/body element:

html, body {
- overflow-x: hidden;
}

You can set a wrapper element's (i.e div) maximum width to 100vw and overflow-x:hidden to archive the same thing.

Upvotes: 16

artkwi
artkwi

Reputation: 1

In my case top: 0 works with behavior: 'smooth, but not with behavior: 'auto'. With default behavior: 'auto' value top: 0 not working, but any other values work e.g:

window.scroll({
  top: 1,
});

Upvotes: 0

Heath Dunlop
Heath Dunlop

Reputation: 3

inside of your Page/Layout component import next router

import Router from 'next/router';

// you can then hook into there events

Router.onRouteChangeStart = () => {

};

Router.onRouteChangeComplete = () => {
  window.scroll({
    top: 0,
    left: 0,
  });
};

Router.onRouteChangeError = () => {

};

const Page = props => { 
  return <div>{props.children}</div>
}

Upvotes: 0

Noob
Noob

Reputation: 2807

I had the same issue when my page would not render at the top. In my case in my global.css i had this:

html {
  font-size: 62.5%;
  scroll-behavior: smooth;
}

After removing scroll-behavior: smooth; everything started working as expected.

Upvotes: 15

Miguel T
Miguel T

Reputation: 31

I was struggling with this issue for a few days and found the solution.

The issue for some unknown reason was that NextJS has some bug when a global html style is imported. I had html class in my global styles.scss import that was loaded into my main wrapper. Once I removed the html from the import the scrolling issues stopped and pages loaded as they would on a static site.

Found the solution here https://github.com/zeit/next.js/issues/7594

Upvotes: 3

Aessandro
Aessandro

Reputation: 5761

Ended up doing this in the main app.js file:

  componentDidMount() {
    Router.events.on('routeChangeComplete', () => {
      window.scroll({
        top: 0,
        left: 0,
        behavior: 'smooth'
      });
    });
  }

Upvotes: 19

demkovych
demkovych

Reputation: 8847

Wrap your App component with:

<ScrollToTop>
  ... all components there
</ScrollTop>

ScrollTop component:

import React, { useEffect } from 'react';
import { withRouter } from 'react-router-dom';

const ScrollToTop = ({ children, location: { pathname, search } }) => {
  useEffect(() => {
    try {
      window.scroll({
        top: 0,
        left: 0,
        behavior: 'smooth'
      });
    } catch (error) {
      // just a fallback for older browsers
      window.scrollTo(0, 0);
    }
  }, [pathname, search]);

  return children;
};

export default withRouter(ScrollToTop);

Upvotes: -7

Related Questions