molefrog / molefrog/wouter

Feature request: scroll restoration

Open
#300 15 comments 17 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature
Dominant language
TypeScript
Stars
7.9k
Forks
190
Avg merge
12h 50m
Merged PRs (30d)
3

Description

This has been requested before: #132, (partially) #166, #189 - but the suggested code is an incomplete solution:

import { useEffect } from "react";
import { useLocation } from "wouter";

export default function ScrollToTop() {
  const [ pathname ] = useLocation();

  useEffect(() => {
    window.scrollTo(0, 0);
  }, [pathname]);

  return null;
}

This will scroll to the top of the page on any navigation, including when the user presses the back / forward history buttons, and when the user navigates in ways that only affect part of the page (e.g. changing a tab component which records the current tab in the URL). It will also have a brief flicker due to using useEffect rather than useLayoutEffect. A more complete solution would only reset the scroll position when navigating to new pages, restoring previous positions when navigating forward / back, and allowing an override on links to disable scrolling to the top of the page.

React Router provides this as a separate component, but with some necessary integration with the core. That seems like a reasonable approach to follow here too, since it fits the philosophy of not bloating the core library (saving space for people who don't need the feature).

https://reactrouter.com/en/main/components/scroll-restoration

Their (MIT licensed) code shows that there are quite a few considerations here, so it seems beneficial to offer this in the library rather than having each user recreate the functionality for themselves. This will also make it possible to add integrations such as allowing specific links to bypass the scrolling behaviour.

Generally, their approach:

  • takes over the native scroll behaviour (i.e. when the whole page actually switches) by setting history.scrollRestoration (docs)
  • listens for the pagehide event to capture current scroll position before navigating to another page (also captures refreshing) (docs)
  • stores scroll locations in session storage (likely to avoid taking over the state parameter used in the history API)
  • provides a custom implementation of scrolling to anchor elements (likely due to disabling the browser's native handling; this might not be required, but worth finding out what the disadvantages are of allowing native scroll handling)
  • gives links / navigate the ability to bypass auto-scrolling by setting a flag
  • updates the scroll position inside a useLayoutEffect call to avoid flickering that useEffect would cause.

I think a minimal approach could:

  • listen for pagehide events to capture scroll position
  • record this position in the history API for the current page (by calling history.replaceState) - this can be put into the state object since currently it's always just set to null, which avoids the need to use session storage [edit: actually this probably won't work because by the time pagehide fires, the history has (probably?) already updated, so using session storage might be a requirement]
  • set up a useLayoutEffect with useLocation()[0] as a dep. Internally this can check history.state to see if it needs to scroll
    • it would be better if this could depend on the history.state object directly - would it be possible to expose this from useLocation somehow?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the useLocation integration and the linked React Router scroll-restoration implementation. Trace how navigation, history.state, pagehide, and link or navigate options are exposed in wouter. Done means a focused scroll-restoration feature supports new-page resets, back/forward restoration, anchor handling, and an opt-out without bloating the core.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend, web-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.