Skip to content

Conversation

@pascalbaljet
Copy link
Member

@pascalbaljet pascalbaljet commented Oct 9, 2025

Fixes #2122.
Fixes #2402.

Here's a summary of the deep dive I did to debug this issue.

We rely on the PopStateEvent to detect when the user clicks the back button in the browser to retrieve the previous page from history and swap the component/page accordingly. However, at least on iOS, in browsers other than Safari (which all use WebKit/WKWebView), this event isn't always fired. As a result, the user can get thrown out of the Inertia app and back to the page they were on before entering it.

According to the MDN Docs, the event is only triggered by a browser action, which effectively means a user interaction like clicking the back button.

The popstate event is only triggered by doing a browser action such as a clicking on the back button (or calling history.back() in JavaScript). And the event is only triggered when the user navigates between two history entries for the same document.

Here's the problem: when you visit a subsequent page, Inertia mutates the browser history twice.

  1. It first replaces the current page to store the scroll regions.
  2. Then it pushes the new page as a new entry in the browser history.

Since these two operations happen almost instantly, the browser doesn't treat them as a user interaction but rather as a programmatic update. This behavior exists to protect users from malicious sites that could fill up your browser history with junk, making the back button practically useless. So instead of firing the PopStateEvent, the browser just takes you right out of the app.

I'm not entirely sure why we store the scroll regions on leaving the page, since that already happens when scrolling on the current page. When I removed it, all tests still passed, but I wasn't fully comfortable removing it.

So instead, we're now only replacing the state when the scroll data has actually changed. Since scroll positions are continuously saved as users scroll (via event listeners in scroll.ts), and since scroll positions rarely change at the exact moment of navigation, this effectively prevents the unnecessary replaceState() call that was happening right before pushState() during page navigation.

@pascalbaljet pascalbaljet changed the title Prevent replacing history state when scroll regions are unchanged. Prevent replacing history state when scroll regions are unchanged to fix popstate behavior in WebKit Oct 9, 2025
@pascalbaljet pascalbaljet merged commit 667317b into master Oct 9, 2025
12 checks passed
@pascalbaljet pascalbaljet deleted the fix-back-button-webkit branch October 9, 2025 15:32
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.

IOS Chrome does not remember browse history [2.x] Browser "Back" button does not return to the previous page with prefetch on mobile devices

2 participants