Search code examples
scrollnavigationsveltesapper

history.replaceState() not working with history.scrollRestoration = 'auto' in Svelte/Sapper


I am using history.replaceState() to update the query params of my page without causing a page reload as suggested in this SO answer.

function setQueryParam ({ name, value }) {
  const params = new URLSearchParams(window.location.search)

  params.set(name, value)
  history.replaceState({}, '', decodeURIComponent(`${window.location.pathname}?${params}`))
}

I am also storing the scroll position of the user with the following line:

history.scrollRestoration = 'auto'

When navigating from one page to another, scrollRestoration works fine - the scroll position is maintained between pages. However, after I change the query params with my setQueryParam function, scroll restoration no longer works.

Why is this happening?

Note: the same code works fine outside of Svelte/Sapper, using HTML and JavaScript only.


Solution

  • As a client-side router, Sapper has to hijack scroll management & restoration a good deal to emulate the behaviour you normally get when you fully reload the browser on each page change.

    To do that, it uses history's state to know the scroll position to restore.

    When you're using history.replaceState, you're changing the state (it's the first argument you place to replaceState). And so, Sapper don't find its restore scroll data when you later pop the state.

    You can try to manually preserve the history state like this:

    // notice the first argument
    history.replaceState(history.state, '', decodeURIComponent(`${window.location.pathname}?${params}`))
    

    I don't think history.scrollRestoration actually has any effect in Sapper.