Check your version
This post assumes you're using React Router v6. If not, find your version below.

As of today, React Router v6 doesn’t ship with support for preventing transitions. Once this issue is resolved, we’ll update this post with the recommended way to prevent transitions in your app.

For now, here’s a very hacky not “approved” approach that “works”.

import * as React from "react";
import {
UNSAFE_NavigationContext as NavigationContext
} from "react-router-dom";
export function useBlocker(blocker, when = true) {
const { navigator } = React.useContext(NavigationContext);
React.useEffect(() => {
if (!when) return;
const unblock = navigator.block((tx) => {
const autoUnblockingTx = {
...tx,
retry() {
unblock();
tx.retry();
}
};
blocker(autoUnblockingTx);
});
return unblock;
}, [navigator, blocker, when]);
}
export default function usePrompt(message, when = true) {
const blocker = React.useCallback(
(tx) => {
if (window.confirm(message)) tx.retry();
},
[message]
);
useBlocker(blocker, when);
}

Now you can usePrompt in your app. usePrompt receives two arguments – when and message. when is a boolean that if true, will show the user a prompt with the message when they try to navigate away.

function Form() {
const [name, setName] = React.useState("");
const [email, setEmail] = React.useState("");
const [note, setNote] = React.useState("");
const isDirty = () => {
return name.length > 0
|| email.length > 0
|| note.length > 0;
};
usePrompt(
"Are you sure you want to leave?",
isDirty()
)
return (
<form
onSubmit={(e) => {
e.preventDefault();
alert("Submitted!");
setName("");
setEmail("");
setNote("");
}}
>
...
</form>
);
}

Here’s a Codesandbox with the above implementation.

Want to learn more?
If you liked this post and want to learn more, check out our free Comprehensive Guide to React Router.

Before you leave

I know, "another newsletter pitch" - but hear me out. Most JavaScript newsletters are terrible. When's the last time you actually looked forward to getting one? Even worse, when's the last time you actually read one rather than just skim it?

We wanted to change that, which is why we created Bytes. The goal was to create a JavaScript newsletter that was both educational and entertaining. 69,546 subscribers and an almost 50% weekly open rate later, it looks like we did it.

Delivered to 69,546 developers every Monday

Avatar for Tyler McGinnis

Tyler McGinnis

CEO of ui.dev. Obsessed with teaching, writing, swimming, biking, and running.

Share this post

Want more react-router?

This is part of our React Router course. You can take the rest of the course by starting a free 3-day trial.