Skip to content

Restore scroll position on back/forward with history:"reload"#3704

Closed
scriptogre wants to merge 1 commit into
bigskysoftware:four-devfrom
scriptogre:fix/history-reload-scroll-restoration
Closed

Restore scroll position on back/forward with history:"reload"#3704
scriptogre wants to merge 1 commit into
bigskysoftware:four-devfrom
scriptogre:fix/history-reload-scroll-restoration

Conversation

@scriptogre

@scriptogre scriptogre commented Mar 14, 2026

Copy link
Copy Markdown
Collaborator

Problem

history:"reload" loses scroll position on back/forward navigation.

1. User scrolls to Y=500 on /page-a
2. Clicks a boosted link to /page-b
3. Presses back
4. /page-a reloads at Y=0

Solution

Track scroll positions in sessionStorage, keyed by a unique index per history entry. Same pattern used by SvelteKit, React Router, and TanStack Router.

1. User scrolls to Y=500 on /page-a
2. Clicks a boosted link: scrollY saved to sessionStorage
3. Presses back
4. /page-a reloads, reads scrollY from sessionStorage, scrolls to 500

Scroll is saved via a debounced (350ms) scroll listener, on pushState, and on popstate. The 350ms debounce stays under Safari's replaceState rate limit. After reload, scroll is restored via requestAnimationFrame after the load event.

How to test

<body hx-boost:inherited="true">
<meta name="htmx-config" content='{"history":"reload"}'>
  1. Scroll down on a page, click a boosted link
  2. Press back : scroll should restore
  3. Press forward, then back again: scroll should persist across cycles

When history:"reload" is set, pressing back/forward calls location.reload(),
which destroys the browser's native scroll restoration.

This patch tracks scroll positions in sessionStorage, keyed by a unique index
assigned to each history entry. Scroll is saved via a debounced scroll listener
(350ms, safe for Safari's replaceState rate limit), on pushState, and on
popstate. After reload, the saved position is restored via requestAnimationFrame
after the load event.

Includes Playwright e2e tests covering back, forward, and repeated cycles.
@scriptogre scriptogre closed this Mar 17, 2026
@scriptogre
scriptogre deleted the fix/history-reload-scroll-restoration branch March 19, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant