Skip to content

Instantly share code, notes, and snippets.

@yuvalkarmi
Last active April 30, 2024 13:42
Show Gist options
  • Save yuvalkarmi/ab7944b2da693c71cf697db6a47e5b5d to your computer and use it in GitHub Desktop.
Save yuvalkarmi/ab7944b2da693c71cf697db6a47e5b5d to your computer and use it in GitHub Desktop.
How to block a user from navigating away in NextJS when clicking on Link component
/*
In standard web apps, when users navigate away to a different page or website or attempt to refresh a page,
we can use the window event listener `beforeunload` to help users avoid losing the work.
However, when a user clicks on a native NextJS <Link> component, the navigation is not intercepted
because behind the scenes, no page changes are actually happening.
To intercept user navigation in a NextJS app, we can subscribe to the
router routeChangeError event and throw an error.
Note: we must throw an Error string - not a `new Error()` - which is why in the code below, we have
// eslint-disable-next-line no-throw-literal
above the line throwing the error.
*/
import Router from "next/router";
import { useEffect } from 'react';
const YourComponent = () => {
// Relevent code begin
const shouldBlockNavigation = true; // set this up however you want
useEffect(() => {
const nativeBrowserHandler = (event) => {
if (shouldBlockNavigation) {
event.preventDefault();
event.returnValue = '';
}
};
const nextNavigationHandler = (url) => {
if (shouldBlockNavigation) {
if (!window.confirm('Navigate away? Changes you made may not be saved.')) {
Router.events.emit('routeChangeError')
// eslint-disable-next-line no-throw-literal
throw "Abort route change by user's confirmation."
}
}
};
window.addEventListener('beforeunload', nativeBrowserHandler);
Router.events.on("beforeHistoryChange", nextNavigationHandler);
// On component unmount, remove the event listener
return () => {
window.removeEventListener('beforeunload', nativeBrowserHandler);
Router.events.off("beforeHistoryChange", nextNavigationHandler);
};
}, [shouldBlockNavigation]);
// Relevent code end
return <div>Your Component</div>
}
@sahmed007
Copy link

So frickin' glad I came across this. This worked for me on Next 13.2.4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment