I have an issue when navigating into another page, its position will remain like the page before. So it won't scroll to top automatically.
I've also tried to use window.scrollTo(0, 0)
on onChange
router. I've also used scrollBehavior
to fix this issue but it didn't work. Any suggestions about this?

- 436
- 6
- 22

- 3,235
- 2
- 11
- 9
-
Could you not do the logic in `componentDidMount` of the new route's component? – Yuya Apr 28 '16 at 02:38
-
just add `document.body.scrollTop = 0;` in the `componentDidMount` of the component you are moving to – John Ruddell Apr 28 '16 at 03:46
-
@Kujira i've already added scrollTo inside componentDidMount() but it didnt work. – adrian hartanto Apr 28 '16 at 03:58
-
@JohnRuddell That was not working too. – adrian hartanto Apr 28 '16 at 03:59
-
I have to use document.getElementById('root').scrollTop = 0 in order to work – Mr. 14 Mar 17 '19 at 10:52
-
3There are some good solutions here but what if a link is clicked with an anchor id? – Nathan Hensher Jul 15 '19 at 09:43
-
I did try this but it didn't work out. – meDeepakJain Nov 11 '19 at 04:06
-
And, why is it necessary to set the scroll position. React JS should automatically move the scroll to top because we navigated to a different page in this case. Isn't? – meDeepakJain Nov 11 '19 at 04:07
-
WARNING: as per the discussion [here](https://stackoverflow.com/questions/31119786/window-scrollto-in-react-components), `window.scrollTo` works only when the scroll behavior is set to the `html` tag. If the scroll is set to `body`, then you need to do `document.querySelector("body").scrollTo(0,0)`. – Paul Razvan Berg Oct 06 '22 at 11:37
36 Answers
but classes are so 2018
ScrollToTop implementation with React Hooks
ScrollToTop.js
import { useEffect } from 'react';
import { withRouter } from 'react-router-dom';
function ScrollToTop({ history }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return () => {
unlisten();
}
}, []);
return (null);
}
export default withRouter(ScrollToTop);
Usage:
<Router>
<Fragment>
<ScrollToTop />
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</Fragment>
</Router>
ScrollToTop can also be implemented as a wrapper component:
ScrollToTop.js
import React, { useEffect, Fragment } from 'react';
import { withRouter } from 'react-router-dom';
function ScrollToTop({ history, children }) {
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return () => {
unlisten();
}
}, []);
return <Fragment>{children}</Fragment>;
}
export default withRouter(ScrollToTop);
Usage:
<Router>
<ScrollToTop>
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</ScrollToTop>
</Router>

- 31,043
- 20
- 111
- 145
-
26Best solution I have seen so far on the internet. I just a bit confused why react-router project does not add a property `scrollToTop` to `
`. It seems to be very frequently used feature. – stanleyxu2005 Apr 09 '20 at 07:37 -
-
5you should check `action !== 'POP'`. Listener accept action as 2th arg – Atombit Aug 24 '20 at 14:34
-
6
-
2
-
10It works but it not handling back behaviour. I means when go back to previous page, previous page also load from the the top of scroll. For example I have list of 100 items, and clicking on particular item it navigate to another page. Now, when I if I click on list item which is scrolled to the down on first page and go to another page, another page will load from scroll to top, but if I go back then first page also load from scroll to top. However it should be load where we left off I mean from the bottom of scroll. – Kishan Bharda Jan 23 '21 at 07:44
-
10For TypeScript users, the correct type of `history` prop is `History` from `import { History } from "history";` – Owl Apr 24 '21 at 09:30
-
It works for going forward on the website, but while pressing back, the page shifts either a bit up or a bit down. Any solutions for that? – Jesswin Oct 23 '21 at 18:51
-
-
This works but also disrupts user experience. It doesn't handle the back behavior, doesn't work with URL query params (`?name=jake`), doesn't work with URL fragments (`#heading-anchor`) etc. These are the cases where you shouldn't scroll to the top. Folks, please do understand the shortcomings of this before implementing this in your project. The [answer by @Saeed](https://stackoverflow.com/a/61602724/3049655) is better. – Spikatrix Dec 26 '22 at 06:23
React 16.8+
If you are running React 16.8+ this is straightforward to handle with a component that will scroll the window up on every navigation:
Here is in scrollToTop.js component
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
Then render it at the top of your app, but below Router
Here is in app.js
import ScrollToTop from "./scrollToTop";
function App() {
return (
<Router>
<ScrollToTop />
<App />
</Router>
);
}
Or in index.js
import ScrollToTop from "./scrollToTop";
ReactDOM.render(
<BrowserRouter>
<ScrollToTop />
<App />
</BrowserRouter>
document.getElementById("root")
);

- 2,664
- 1
- 13
- 12
-
3Yep, this is suitable solution that works well in react app using hooks. – Meet Zaveri Sep 10 '21 at 04:07
-
This was working for me before but it has stopped working. Does anyone know why? I have not even updated react-router! Thank you in advance – Javier Guzmán Sep 14 '21 at 13:26
-
10
-
2Thanks, this also work for "react-router-dom": "^6.2.1" and "react": "^17.0.2". – D4ITON Feb 19 '22 at 14:18
-
-
It doesn't seem to work with `useLocation` passing -1 to go back to the last page. Thoughts? – Fazwelington Aug 02 '22 at 19:44
-
@volley Typically users would want to be in the position they were on when going back. That's good UX. – Spikatrix Dec 26 '22 at 06:03
This answer is only for v4 and not later versions.
The documentation for React Router v4 contains code samples for scroll restoration. Here is their first code sample, which serves as a site-wide solution for “scroll to the top” when a page is navigated to:
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop)
Then render it at the top of your app, but below Router:
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
// or just render it bare anywhere you want, but just one :)
<ScrollToTop/>
^ copied directly from the documentation
Obviously this works for most cases, but there is more on how to deal with tabbed interfaces and why a generic solution hasn't been implemented.

- 7,529
- 2
- 20
- 22
-
5You should also reset keyboard focus at the same time as scrolling to top. I wrote a thing to take care of it: https://github.com/oaf-project/oaf-react-router – danielnixon May 09 '19 at 05:00
-
4this extract from the docs `Because browsers are starting to handle the “default case” and apps have varying scrolling needs (like this website!), we don’t ship with default scroll management. This guide should help you implement whatever scrolling needs you have.` makes me sad, because all the options they go on to give code examples for, could actually be baked into the control via property settings, with some conventions around default behavior that can then be changed. This feels super hacky and unfinished, imho. Means only advanced react devs can do routing properly and no #pitOfSuccess – snowcode Sep 19 '19 at 09:15
-
3oaf-react-router appears to address important accessibility issues that all the `work-arounds` here have ignored. +100 for @danielnixon – snowcode Sep 19 '19 at 09:28
-
ScrollToTop is not defined. How to import it in App.js? import ScrollToTop from './ScrollToTop' doesn't work. – anhtv13 Jul 22 '20 at 09:12
-
@anhtv13, you should ask that as a new question so you can include the code you are referencing. – mtl Jul 22 '20 at 14:04
-
My question is on your answer. It's not clear how to use the ScrollToTop. By the way, I found out the import on zurfyx's answer. – anhtv13 Jul 23 '20 at 02:10
-
1you should check `action !== 'POP'`. Listener accept action as 2th arg – Atombit Aug 24 '20 at 14:35
-
This is a helpful answer but mentioning index.js as the location where App is rendered would improve it. Also for me the idea of "or just render it bare anywhere you want" does not work because of error about the component not having any children or some such. – biomiker Nov 05 '21 at 19:12
A React Hook you can add to your Route component. Using useLayoutEffect
instead of custom listeners.
import React, { useLayoutEffect } from 'react';
import { Switch, Route, useLocation } from 'react-router-dom';
export default function Routes() {
const location = useLocation();
// Scroll to top if path changes
useLayoutEffect(() => {
window.scrollTo(0, 0);
}, [location.pathname]);
return (
<Switch>
<Route exact path="/">
</Route>
</Switch>
);
}
Update: Updated to use useLayoutEffect
instead of useEffect
, for less visual jank. Roughly this translates to:
useEffect
: render components -> paint to screen -> scroll to top (run effect)useLayoutEffect
: render components -> scroll to top (run effect) -> paint to screen
Depending on if you're loading data (think spinners) or if you have page transition animations, useEffect
may work better for you.

- 2,391
- 1
- 15
- 8
-
3Strange, but throwing error as `Cannot read properties of undefined (reading 'location')` – Pardeep Jain Jan 23 '22 at 07:40
This answer is for legacy code, for router v4+ check other answers
<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}>
...
</Router>
If it's not working, you should find the reason. Also inside componentDidMount
document.body.scrollTop = 0;
// or
window.scrollTo(0,0);
you could use:
componentDidUpdate() {
window.scrollTo(0,0);
}
you could add some flag like "scrolled = false" and then in update:
componentDidUpdate() {
if(this.scrolled === false){
window.scrollTo(0,0);
scrolled = true;
}
}

- 24,652
- 10
- 111
- 109
-
I've updated answer w/o getDomNode at all because in fact I never had to use it for scroll to top. I've just use `window.scrollTo(0,0);` – Lukas Liesis Apr 28 '16 at 06:56
-
4`onUpdate` hook is deprecated in react-router v4 - just wanna point that out – Dragos Rizescu Mar 18 '17 at 16:38
-
@DragosRizescu Any guidance on using this method without the `onUpdate` hook? – Matt Voda Jun 06 '17 at 19:22
-
1@MattVoda You can listen for changes on history itself, check examples: https://github.com/ReactTraining/history – Lukas Liesis Jun 06 '17 at 20:31
-
4@MattVoda wrote an answer below on how you can achieve that with react-router-v4 – Dragos Rizescu Jun 08 '17 at 14:50
-
@DragosRizescu good job :) I'm still leaving this answer for legacy code – Lukas Liesis May 17 '18 at 21:45
-
For react-router v4, here is a create-react-app that achieves the scroll restoration: http://router-scroll-top.surge.sh/.
To achieve this you can create decorate the Route
component and leverage lifecycle methods:
import React, { Component } from 'react';
import { Route, withRouter } from 'react-router-dom';
class ScrollToTopRoute extends Component {
componentDidUpdate(prevProps) {
if (this.props.path === this.props.location.pathname && this.props.location.pathname !== prevProps.location.pathname) {
window.scrollTo(0, 0)
}
}
render() {
const { component: Component, ...rest } = this.props;
return <Route {...rest} render={props => (<Component {...props} />)} />;
}
}
export default withRouter(ScrollToTopRoute);
On the componentDidUpdate
we can check when the location pathname changes and match it to the path
prop and, if those satisfied, restore the window scroll.
What is cool about this approach, is that we can have routes that restore scroll and routes that don't restore scroll.
Here is an App.js
example of how you can use the above:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Lorem from 'react-lorem-component';
import ScrollToTopRoute from './ScrollToTopRoute';
import './App.css';
const Home = () => (
<div className="App-page">
<h2>Home</h2>
<Lorem count={12} seed={12} />
</div>
);
const About = () => (
<div className="App-page">
<h2>About</h2>
<Lorem count={30} seed={4} />
</div>
);
const AnotherPage = () => (
<div className="App-page">
<h2>This is just Another Page</h2>
<Lorem count={12} seed={45} />
</div>
);
class App extends Component {
render() {
return (
<Router>
<div className="App">
<div className="App-header">
<ul className="App-nav">
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/another-page">Another Page</Link></li>
</ul>
</div>
<Route exact path="/" component={Home} />
<ScrollToTopRoute path="/about" component={About} />
<ScrollToTopRoute path="/another-page" component={AnotherPage} />
</div>
</Router>
);
}
}
export default App;
From the code above, what is interesting to point out is that only when navigating to /about
or /another-page
the scroll to top action will be preformed. However when going on /
no scroll restore will happen.
The whole codebase can be found here: https://github.com/rizedr/react-router-scroll-top

- 49,270
- 33
- 114
- 141

- 3,380
- 5
- 31
- 42
-
2Just what I was looking for! I had to add the scrollTo in the componentDidMount of the ScrollToTopRoute, as I have my routes wrapped in a Switch component (I also removed the if as I wanted it to fire on each mount) – tocallaghan Jun 20 '17 at 05:07
-
In the render of your ScrollToTopRoute, you don't need to specify the render={props => (
)}. Simply using the {...rest} in the route will work. – Finickyflame Oct 20 '17 at 22:19 -
This answer provided me with all the tools to achieve a solution and fix my bug. Thank you so much. – Null isTrue Aug 01 '18 at 02:46
-
It is not working completely. If you follow the project link then it will be default open the `Home`. Now scroll to the bottom of the `Home` and now go to 'AnotherPage' and don't scroll. Now if you come again to `Home`, this page will be scrolled to the top. But according to your answer, the `home` page should be kept scrolled. – aditya81070 May 28 '19 at 18:41
-
} exact={true}/> Please how can i use the title attribute on the ScrollToTopRoute component ? – mhannani Dec 18 '20 at 00:14
It is noteable that the onUpdate={() => window.scrollTo(0, 0)}
method is outdated.
Here is a simple solution for react-router 4+.
const history = createBrowserHistory()
history.listen(_ => {
window.scrollTo(0, 0)
})
<Router history={history}>

- 3,577
- 1
- 15
- 16
-
This should be the correct answer if history is used. It covers all eventualites including clicking on a link to the page you're currently on. Only issue I found is the scrollTo didn't fire and needed to be wrapped in a setTimeout(window.scrollTo(0, 0),0); I still don't understand why but hey ho – sidonaldson May 30 '19 at 09:47
-
5You will have a problems when you add `#` and `?` to the end of our url. In first case you should scroll no to the top in second case you shouldn't scroll at all – Arseniy-II Jul 24 '19 at 07:09
-
4
React hooks 2020 :)
import React, { useLayoutEffect } from 'react';
import { useLocation } from 'react-router-dom';
const ScrollToTop: React.FC = () => {
const { pathname } = useLocation();
useLayoutEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
};
export default ScrollToTop;

- 391
- 6
- 14
-
can you please explain this part? `const ScrollToTop: React.FC = () => {` I dont understand what `ScrollToTop: React.FC` means – beeftosino Jul 20 '20 at 10:34
-
3
FOR 'REACT-ROUTER-DOM v6 & above'
I solved the following issue by creating a wrapper function and wrapping it around all the routes.
Follow the following steps:
1: You need to import the following:
import {Routes, Route, BrowserRouter as Router, useLocation} from 'react-router-dom';
import {useLayoutEffect} from 'react';
2: Write a wrapper function just above the "App" function:
const Wrapper = ({children}) => {
const location = useLocation();
useLayoutEffect(() => {
document.documentElement.scrollTo(0, 0);
}, [location.pathname]);
return children
}
3: Now wrap your routes within the wrapper function:
<BrowserRouter>
<Wrapper>
<Navbar />
<Routes>
<Route exact path="/" element={<Home/>} />
<Route path="/Products" element={<Products/>} />
<Route path="/Login" element={<Login/>} />
<Route path="/Aggressive" element={<Aggressive/>} />
<Route path="/Attendance" element={<Attendance/>} />
<Route path="/Choking" element={<Choking/>} />
<Route path="/EmptyCounter" element={<EmptyCounter/>} />
<Route path="/FaceMask" element={<FaceMask/>} />
<Route path="/Fainting" element={<Fainting/>} />
<Route path="/Smoking" element={<Smoking/>} />
<Route path="/SocialDistancing" element={<SocialDistancing/>} />
<Route path="/Weapon" element={<Weapon/>} />
</Routes>
<Footer />
</Wrapper>
</BrowserRouter>
This should solve the issue.

- 455
- 6
- 14
-
instead of document.documentElement.scrollTo(0, 0) i'd suggest this code: window.scrollTo({ top: 0, behavior: "smooth" }); – majkl zumberi May 11 '22 at 14:36
-
I had the same issue with my application.Using the below code snippet helped me scroll to the top of the page on click of the next button.
<Router onUpdate={() => window.scrollTo(0, 0)} history= {browserHistory}>
...
</Router>
However, the issue still persisted on browser back. After a lot of trials, realized that this was because of the browser window's history object, which has a property scrollRestoration which was set to auto.Setting this to manual solved my problem.
function scrollToTop() {
window.scrollTo(0, 0)
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
}
<Router onUpdate= {scrollToTop} history={browserHistory}>
....
</Router>

- 497
- 5
- 14
In your main component.
Just add this React Hooks (in case you are not using a React class) :
const oldPage = useRef(pathname)
useEffect(() => {
if (pathname !== oldPage.current) {
try {
window.scroll({
top: 0,
left: 0,
behavior: 'smooth'
})
} catch (error) {
// for older browser
window.scrollTo(0, 0)
}
oldPage.current = pathname
}
}, [pathname])

- 651
- 1
- 7
- 17
August-2021
Rather then doing it in every page you can do this in App.js
import { useLocation } from "react-router-dom";
const location = useLocation();
useEffect(() => {
window.scrollTo(0,0);
}, [location]);
Setting location in useEffect
will make sure to scroll to top on every path change.
I want to share my solution for those who are using react-router-dom v5
since none of these v4 solutions did the work for me.
What solved my problem was installing react-router-scroll-top and put the wrapper in the <App />
like this:
const App = () => (
<Router>
<ScrollToTop>
<App/>
</ScrollToTop>
</Router>
)
and that's it! it worked!

- 1,733
- 1
- 16
- 21
Hooks are composable, and since React Router v5.1 we have a useHistory()
hook. So based off @zurfyx's answer I've created a re-usable hook for this functionality:
// useScrollTop.ts
import { useHistory } from 'react-router-dom';
import { useEffect } from 'react';
/*
* Registers a history listener on mount which
* scrolls to the top of the page on route change
*/
export const useScrollTop = () => {
const history = useHistory();
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
});
return unlisten;
}, [history]);
};

- 544
- 5
- 9
-
It's worth nothing that scrollTo() doesn't work in IE11. `window.scrollTop = 0` is a good alternative – Turnip Dec 10 '20 at 05:19
-
1@Nathan my understanding is in IE calling `scrollTo` on an Element doesn't work, but calling it on the `window` object does. See https://caniuse.com/mdn-api_window_scrollto vs https://caniuse.com/mdn-api_element_scrollto – Kris Dover Jan 10 '21 at 22:46
This was my approach based on what everyone else had done in previous posts. Wondering if this would be a good approach in 2020 using location as a dependency to prevent re-renders?
import React, { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function ScrollToTop( { children } ) {
let location = useLocation();
useEffect( () => {
window.scrollTo(0, 0);
}, [ location ] );
return children
}

- 300
- 4
- 15
-
1This is actually the recommended approach on the react router website: https://reactrouter.com/web/guides/scroll-restoration – Alexander Wu Jan 17 '21 at 11:08
-
@Rainning you may refer to my code snippet shared above. It works for me – Nishant Kohli May 24 '21 at 18:30
2021 (React 16) - Based off the comments from @Atombit
Below scrolls to top, but also preserves historic scroll positions.
function ScrollToTop() {
const history = useHistory()
useEffect(() => {
const unlisten = history.listen((location, action) => {
if (action !== 'POP') {
window.scrollTo(0, 0)
}
})
return () => unlisten()
}, [])
return (null)
}
Usage:
<Router>
<ScrollToTop />
<Switch>
<Route path="/" exact component={Home} />
</Switch>
</Router>

- 4,237
- 12
- 42
- 47

- 1,772
- 21
- 26
-
I was looking for this answer. However, my solution is to check that the action is "PUSH" so that a REPLACE does not trigger a scroll to top either. – FMCorz Sep 30 '21 at 11:17
My solution: a component that I'm using in my screens components (where I want a scroll to top).
import { useLayoutEffect } from 'react';
const ScrollToTop = () => {
useLayoutEffect(() => {
window.scrollTo(0, 0);
}, []);
return null;
};
export default ScrollToTop;
This preserves scroll position when going back. Using useEffect() was buggy for me, when going back the document would scroll to top and also had a blink effect when route was changed in an already scrolled document.

- 345
- 7
- 7
With smooth scroll option
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
}, [pathname]);
return null;
}
...
<Router>
<ScrollToTop />
...
</Router>

- 4,757
- 1
- 32
- 23
Utilizing hooks, you can simply insert window.scrollTo(0,0)
in your useEffect
in your code base. Simply implement the code snippet in your app and it should load each page at the top of it's window.
import { useEffect } from 'react';
useEffect(() => {
window.scrollTo(0, 0);
}, []);

- 41
- 2
2022 November Update
Nothing work in react latest version 18.2.0 and react-router-dom 6.4.3. So I implemented this. Worked for me.Hope this helpful for anyone.
ScrollToTop.js
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
const body = document.querySelector('#root');
body.scrollIntoView({
behavior: 'smooth'
}, 500)
}, [pathname]);
return null;
}
Then import and add to browser router in index.js or App.js where your routes defined.
import { BrowserRouter, Routes, Route } from "react-router-dom";
import ScrollToTop from "./ScrollToTop";
function App() {
return (
<div>
<BrowserRouter>
<ScrollToTop />
<Routes>
//your routes
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
(Note: Make sure the index.html
div id="root"
.)

- 638
- 2
- 10
- 19
Since, I use function components, here is how I managed to achieve it.
import { useEffect } from 'react';
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom';
function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
}
const IndexRoutes = () => {
return (
<BrowserRouter>
<ScrollToTop />
<Routes>
<Route exact path="/">
<Home />
</Route>
/* list other routes below */
</Routes>
</BrowserRouter>
);
};
export default IndexRoutes;
You can also refer the code from the below link

- 445
- 6
- 6
For me, window.scrollTo(0, 0)
and document.documentElement.scrollTo(0, 0)
didn't work on all my screens (only worked on 1 screen).
Then, I realized that the overflow (where scrolling is allowed) of my screens were not in window
(because we have some static points, so we putted the overflow: auto
in other div).
I did the following test to realize this:
useEffect(() => {
const unlisten = history.listen(() => {
console.log(document.documentElement.scrollTop)
console.log(window.scrollTop)
window.scrollTo(0, 0);
});
return () => {
unlisten();
}
}, []);
In all the logs, I got 0.
So, I looked for which container I had the scroll in and put an id:
<div id="SOME-ID">
...
</div>
And in my ScrollToTop component I put:
useEffect(() => {
const unlisten = history.listen(() => {
window.scrollTo(0, 0);
document.getElementById("SOME-ID")?.scrollTo(0, 0)
});
return () => {
unlisten();
}
}, []);
Now, when I go to a new route with history.push("/SOME-ROUTE")
my screen go to the top

- 21
- 2
I wrote a Higher-Order Component called withScrollToTop
. This HOC takes in two flags:
onComponentWillMount
- Whether to scroll to top upon navigation (componentWillMount
)onComponentDidUpdate
- Whether to scroll to top upon update (componentDidUpdate
). This flag is necessary in cases where the component is not unmounted but a navigation event occurs, for example, from/users/1
to/users/2
.
// @flow
import type { Location } from 'react-router-dom';
import type { ComponentType } from 'react';
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
type Props = {
location: Location,
};
type Options = {
onComponentWillMount?: boolean,
onComponentDidUpdate?: boolean,
};
const defaultOptions: Options = {
onComponentWillMount: true,
onComponentDidUpdate: true,
};
function scrollToTop() {
window.scrollTo(0, 0);
}
const withScrollToTop = (WrappedComponent: ComponentType, options: Options = defaultOptions) => {
return class withScrollToTopComponent extends Component<Props> {
props: Props;
componentWillMount() {
if (options.onComponentWillMount) {
scrollToTop();
}
}
componentDidUpdate(prevProps: Props) {
if (options.onComponentDidUpdate &&
this.props.location.pathname !== prevProps.location.pathname) {
scrollToTop();
}
}
render() {
return <WrappedComponent {...this.props} />;
}
};
};
export default (WrappedComponent: ComponentType, options?: Options) => {
return withRouter(withScrollToTop(WrappedComponent, options));
};
To use it:
import withScrollToTop from './withScrollToTop';
function MyComponent() { ... }
export default withScrollToTop(MyComponent);

- 49,270
- 33
- 114
- 141
In your router.js
, just add this function in the router
object. This will do the job.
scrollBehavior() {
document.getElementById('app').scrollIntoView();
},
Like this,
**Routes.js**
import vue from 'blah!'
import Router from 'blah!'
let router = new Router({
mode: 'history',
base: process.env.BASE_URL,
scrollBehavior() {
document.getElementById('app').scrollIntoView();
},
routes: [
{ url: "Solar System" },
{ url: "Milky Way" },
{ url: "Galaxy" },
]
});

- 2,057
- 18
- 21
If you want to not only have the scroll position reset to the top when navigating to a new page, but also to maintain the old scroll position when going to a previous page, use the ScrollRestoration
component (available since React Router 6.4).
This component will emulate the browser's scroll restoration on location changes after loaders have completed to ensure the scroll position is restored to the right spot, even across domains.
Simply render it once in your root component:
import { ScrollRestoration } from 'react-router-dom';
function App() {
return <>
<div>Some content...</div>
<ScrollRestoration/>
</>;
}

- 76,500
- 11
- 62
- 80
Here is another method.
For react-router v4 you can also bind a listener to change in history event, in the following manner:
let firstMount = true;
const App = (props) => {
if (typeof window != 'undefined') { //incase you have server-side rendering too
firstMount && props.history.listen((location, action) => {
setImmediate(() => window.scrollTo(0, 0)); // ive explained why i used setImmediate below
});
firstMount = false;
}
return (
<div>
<MyHeader/>
<Switch>
<Route path='/' exact={true} component={IndexPage} />
<Route path='/other' component={OtherPage} />
// ...
</Switch>
<MyFooter/>
</div>
);
}
//mounting app:
render((<BrowserRouter><Route component={App} /></BrowserRouter>), document.getElementById('root'));
The scroll level will be set to 0 without setImmediate()
too if the route is changed by clicking on a link but if user presses back button on browser then it will not work as browser reset the scroll level manually to the previous level when the back button is pressed, so by using setImmediate()
we cause our function to be executed after browser is finished resetting the scroll level thus giving us the desired effect.

- 1,235
- 12
- 20
with React router dom v4 you can use
create a scrollToTopComponent component like the one below
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop)
or if you are using tabs use the something like the one below
class ScrollToTopOnMount extends Component {
componentDidMount() {
window.scrollTo(0, 0)
}
render() {
return null
}
}
class LongContent extends Component {
render() {
<div>
<ScrollToTopOnMount/>
<h1>Here is my long content page</h1>
</div>
}
}
// somewhere else
<Route path="/long-content" component={LongContent}/>
hope this helps for more on scroll restoration vist there docs hare react router dom scroll restoration

- 19
- 4
Using useEffect() - Solution for Functional Component
useEffect(() => {
window.history.scrollRestoration = 'manual';}, []);

- 31
- 2
My only solution was to add a line of code to each file like for example:
import React from 'react';
const file = () => { document.body.scrollTop = 0; return( <div></div> ) }

- 19
- 4
I used Typescript in my project. This worked for me:
// ScrollToTop.tsx
import {useEffect, useRef} from 'react'
import {withRouter} from 'react-router-dom'
const ScrollToTopComponent = () => {
const mounted = useRef(false)
useEffect(() => {
if (!mounted.current) {
//componentDidMount
mounted.current = true
} else {
//componentDidUpdate
window.scrollTo(0, 0)
}
})
return null
}
export const ScrollToTop = withRouter(ScrollToTopComponent)
// usage in App.tsx
export default function App() {
return (
<Router>
<ScrollToTop />
<OtherRoutes />
</Router>
)
}

- 608
- 5
- 6
For my app, it's essential to have ability to scroll up when navigating by links. But it's also essential to not scroll anything when clicking on tab labels (which are also links). Also, my app has an advanced layout so scrollable containers could be different depending on the layout of the current page and where the link follows.
So here's my solution that works for me:
Introduce RouterLink
wrapper around react-router-dom
's Link
that adds onClick handler. When link is clicked, it finds the nearest scrolled container and scrolls it up. It's possible to opt-out of this behavior by specifying preserveScroll
(that's the default behavior of the original Link.
Hope that helps.
// Helper to find nearest scrolled parent of a given node
const getScrollParent = (node) => {
if (!node) {
return null;
}
if (node.scrollTop > 0) {
return node;
} else {
return getScrollParent(node.parentNode);
}
};
interface RouterLinkProps extends LinkProps {
preserveScroll?: boolean;
}
export const RouterLink: React.FC<RouterLinkProps> = ({ preserveScroll = false, ...linkProps }) => {
const handleClick = useCallback(
(val) => {
const targetEl = val?.target;
if (!targetEl || preserveScroll) {
return;
}
const scrolledContainer = getScrollParent(targetEl);
if (scrolledContainer) {
scrolledContainer.scrollTo({
top: 0,
left: 0,
behavior: 'smooth',
});
}
},
[preserveScroll],
);
const extraProps = useMemo(() => {
if (!preserveScroll) {
return {
onClick: handleClick,
};
}
return {};
}, [handleClick, preserveScroll]);
return <Link {...linkProps} {...extraProps} />;
};
Now, I can use this wrapper and get desired behavior and enough control to adjust it. Like this:
<RouterLink to="/some/path">My Link that scrolls up</RouterLink>

- 3,993
- 1
- 29
- 23
I found that ReactDOM.findDomNode(this).scrollIntoView()
is working. I placed it inside componentDidMount()
.

- 3,235
- 2
- 11
- 9
-
1it's undocumented internal stuff that might change w/o noticing and you code would stop working. – Lukas Liesis Apr 28 '16 at 06:18
For smaller apps, with 1-4 routes, you could try to hack it with redirect to the top DOM element with #id instead just a route. Then there is no need to wrap Routes in ScrollToTop or using lifecycle methods.

- 1
- 2
for react-router-dom V5 react-router-dom V5 scroll to top
import React, { useEffect } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useLocation,
withRouter
} from 'react-router-dom'
function _ScrollToTop(props) {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return props.children
}
const ScrollToTop = withRouter(_ScrollToTop)
function App() {
return (
<div>
<Router>
<ScrollToTop>
<Header />
<Content />
<Footer />
</ScrollToTop>
</Router>
</div>
)
}

- 44
- 7
-
Generally it's helpful to put the contents from the document you've linked to in the answer itself, incase the destination changes or becomes unreachable. You can keep the link though, for reference! – brandonscript Oct 24 '21 at 17:50
-
@brandonscript it's updated with the content. i put the link so that content writer can get the full credit for taking the time to write the content and it will be helpful for others to read the whole content. but you right if the destination changes the putting the content will also be helpful – Surafel Getachew Oct 25 '21 at 12:19
render() {
window.scrollTo(0, 0)
...
}
Can be a simple solution in case the props are not changed and componentDidUpdate() not firing.

- 175
- 1
- 8
This is hacky (but works): I just add
window.scrollTo(0,0);
to render();

- 350
- 2
- 6
-
2so it will scroll up every time state changes and re-render happens, not when navigation changes. Just check my answer – Lukas Liesis Feb 27 '17 at 07:38