
Browsers try to be helpful.
When a user refreshes a page normally, such as by clicking the refresh button or pressing F5, the browser often restores the page to the same scroll position after reload. In many cases, this is exactly what users expect.
But in real applications, this behavior is not always desirable.
For example, you may want a refreshed page to always start from the top when showing a dashboard, onboarding flow, generated report, documentation page, or any view where the previous scroll position could confuse the user.
Fortunately, modern browsers provide a native API for this.
The Native Solution: history.scrollRestoration
The cleanest way to control this behavior is with the History API’s scrollRestoration property.
The key line is simple:
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
Setting the value to 'manual' tells the browser:
Do not automatically restore the previous scroll position after navigation or refresh. Let the page handle it.
This is much cleaner than waiting for the page to load and then forcing scrollTop = 0 with a timer.
Understanding the Default Browser Behavior
By default, browsers usually behave as if scrollRestoration is set to 'auto'.
The demo code below simulates that behavior by saving the current scroll position, resetting the container to the top, and then restoring the saved position on the next animation frame.
function runAutoDemo() {
if ('scrollRestoration' in history) {
history.scrollRestoration = 'auto';
}
const scroller = document.querySelector('#auto-demo .demo-window');
sessionStorage.setItem('auto-demo-scroll', scroller.scrollTop);
scroller.scrollTop = 0;
requestAnimationFrame(() => {
scroller.scrollTop = Number(
sessionStorage.getItem('auto-demo-scroll') || 0
);
});
}
This mirrors what users often see after a normal refresh: the page loads, then jumps back to the section they were reading before.
That behavior is useful for long articles, product listings, and feeds. But for pages where state should reset on reload, it can feel wrong.
Switching to Manual Scroll Restoration
The better approach is to explicitly tell the browser not to restore the old scroll position.
In the demo, the manual version still records the current scroll position, but it does not restore it after the simulated refresh.
function runManualDemo() {
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
const scroller = document.querySelector('#manual-demo .demo-window');
sessionStorage.setItem('manual-demo-scroll', scroller.scrollTop);
scroller.scrollTop = 0;
}
The important part is this:
history.scrollRestoration = 'manual';
Once this is set, the page controls the scroll position itself. If you want the page to start at the top, you can let it load naturally at scrollTop = 0.
The Two Supported Values
history.scrollRestoration supports two values:
auto
The browser is allowed to restore the previous scroll position. This is the default behavior.
manual
The browser should not restore the previous scroll position automatically. The page is responsible for controlling scroll.
The demo includes a simple mode switcher:
function setScrollRestoration(mode) {
if ('scrollRestoration' in history) {
history.scrollRestoration = mode;
}
document.querySelector('#mode-value').textContent = mode;
}
This makes the behavior easy to test. Set the mode to 'auto', scroll down, and simulate a refresh. The scroll position comes back. Set the mode to 'manual', repeat the same steps, and the page stays at the top.
What About Unsupported Browsers?
Modern browsers have supported history.scrollRestoration for a long time, including mobile browsers.
For older browsers that do not support it, you can still use a fallback. It is less elegant, because timing-based solutions can be fragile, but it works when legacy support is required.
function fallbackToTop() {
if (!('scrollRestoration' in history)) {
setTimeout(() => {
window.scrollTo(0, 0);
}, 250);
}
}
This fallback waits briefly after load, then forces the window back to the top.
Use this only when necessary. If the native API exists, prefer it.
Practical Recommendation
For most modern projects, add this near your page initialization code:
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
Use 'auto' when preserving position helps the user continue where they left off. Use 'manual' when refresh should reset the experience.
It is a small browser API, but it replaces an entire class of awkward timer-based scroll fixes with one clear line of intent.
Try It Yourself
Want to see these concepts in action? I’ve created an interactive demo where you can experiment with the code and see real-time results.
Explore more demos from my previous articles in the Demo Gallery.
Happy coding!