Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

PhilKz's avatar

Correct way to intercept back button with Inertia (+ React)

I would like to intercept the back button in my app to prevent users from accidentally leaving an in-progress form. I did some research about how to do this, but the solutions I found all involve using react-router-dom (e.g., https://thewebdev.info/2022/03/07/how-to-intercept-and-handle-browsers-back-button-in-react-router/). This isn't a problem in itself, but since I am using Inertia, it feels like it might be a mistake for some reason to mix using react-router and Inertia. Is there a correct "Inertia way" to intercept the back button, or is it fine to mix using the react-router with Inertia?

0 likes
11 replies
rodrigo.pedra's avatar

I guess you are after adding an listener to Inertia's before event

The before event fires when a request is about to be made to the server. This is useful for intercepting visits.

The primary purpose of this event is to allow you to prevent a visit from happening.

reference: https://inertiajs.com/events#before

PhilKz's avatar

@rodrigo.pedra I tried this approach. Unfortunately it only fires when clicking on links, but not when hitting the browser's back button.

rodrigo.pedra's avatar

@PhilKz weird, I tested locally in an inertia app I have here and it worked with the back button.

I am using Firefox, inertia-vue and inertia-laravel, Are you returning inertia responses form your routes?

PhilKz's avatar

@rodrigo.pedra I'm using inertia-react instead of inertia-vue. Maybe that's the difference? I am also using Firefox, inertia-laravel, and all of my responses are inertia responses.

I tried using 'popstate' instead, but, while this did capture the back button, it did so only after the new page was loaded, while what I need is a way to prevent the browser navigating away in the first place.

Finally, I tried using react-router-dom, but this seems like it will require me to use react router to set the app root rather than Inertia, so it would defeat the purpose of using Inertia.

I guess I'll write some logic to save the state of the form in local storage and restore it if the user cancels out of the back action from the warning in the 'popstate' listener, though this is far from ideal.

rodrigo.pedra's avatar

@PhilKz actually I double checked, to test it I added a confirm alert box to try to prevent navigation.

While the confirm dialog appears when I pressed the browser's back button, the page had already transitioned by then.

Sorry for the false positive... And I am also out of ideas =(

Helmchen's avatar

You could try the window 'beforeunload' event .. i am really not sure what technically happens if you hit the back button. If it fires you can simply event.preventDefault() and return false to abort the unload.

I am using this for the exact same reason (prevent leaving the form in a dirty state), but it's not an SPA so i am not 100% sure.

PhilKz's avatar

@Helmchen Thanks, I tried this. Unfortunately, in an SPA beforeunload only triggers on a refresh and not a back button press.

PhilKz's avatar

Update: I also tried two more approaches which did not work satisfactorily.

  1. Appending a random hash to the URL on every relevant state change and intercepting onhashchange.
useEffect(()=>{
	//Random hash adds "#somerandomcharacters" to the URL.
	history.pushState('','',randomHash());
},[currentQuestion]);

useEffect(()=>{
	window.addEventListener((event)=>{
	//I tried a bunch of variations of what to do here.
	event.preventDefault();
	return confirm("Are you sure you want to navigate away?");
});
},[]);

This resulted in the back button reloading the beginning of the form, rather than going back to the previous page, but still discarding all state/progress.

  1. Using history.pushState to track the state.
useEffect(()=>{
	history.pushState({'currentQuestion':currentQuestion},'','');
},[currentQuestion]);

Same result as above.

PhilKz's avatar

I've come up with a solution to this where I write the state of the form to local storage, then restore the state from the data in local storage (if any) when the form is loaded. This makes it so that the fact that popstate fires after the page has been unloaded doesn't matter, because I can instantly restore the previous state of the form anyway.

    const formId = usePage().props.id;

    useEffect(() => {
        if (window.localStorage.getItem(formId) !== null) {
            let previous = window.localStorage.getItem(formId);
            previous = JSON.parse(previous);
            setCurrentQuestion(previous.currentQuestion);
            setChosenAnswers(previous.chosenAnswers);
        }
    }, []);

    useEffect(() => {
        const formdata= {
            'currentQuestion': currentQuestion,
            'chosenAnswers':chosenAnswers
        }
        window.localStorage.setItem(formId, JSON.stringify(formdata));
    }, [currentQuestion]);

    useEffect(() => {
        window.onpopstate = () => {
			/*This can obviously be replaced with logic prompting to user confirm if they actually want to go back or not.*/
            history.forward();
        }
    }, []);

Advantages:

  • Not only does this deal with intercepting the back button, this also saves the state of the form in case the browser closes unexpectedly.
  • This could be easily extended to save the state to the user's session on the server to preserve their progress across browsers/devices.

Disadvantages:

  • As I've written it, this makes the code more brittle, since any additional piece of state added to the form also has to be manually added here. The order in which this code is called also matters (in that it has to come after all the state it depends on has been declared).

Please let me know if there's anything I haven't thought of with this, or if you have a better way of approaching this problem.

1 like
marcus_hammer's avatar

I need to save data when the user left input fields, but wanted to also save the data if they chose to close the window or hit the back button. After adding the save function to each input statement on blur, I added the following useEffect. This worked great for me. Hope it helps.

// added to input
onBlur={event => handleSave()}

// useEffect to catch closing page or hitting backbutton
useEffect(() => {
        window.onbeforeunload = () => {
            document.activeElement.blur()
        }
        window.addEventListener("popstate", (event) => {
            document.activeElement.blur()
        })
}, [])
1 like

Please or to participate in this conversation.