I am having a modal which while opening pushes a hash to url example.com/#modal
, on browser back button click, I want to recognise that event so that I can toggle the state of modal. the point is, since Im using it with next.js (server side rendering), I will not be having access to window object (correct me if I am wrong). so I need an alternate way to handle the event of browser back button.

- 16,027
- 10
- 55
- 122

- 443
- 3
- 5
- 14
-
did you fixed it? – Shubham Jan 07 '21 at 05:50
6 Answers
You can use next/router
's beforePopState
to act on changes to the session history navigation (back/forward actions), and make sure it'll only happen when leaving the current page.
useEffect(() => {
router.beforePopState(({ as }) => {
if (as !== router.asPath) {
// Will run when leaving the current page; on back/forward actions
// Add your logic here, like toggling the modal state
}
return true;
});
return () => {
router.beforePopState(() => true);
};
}, [router]); // Add any state variables to dependencies array if needed.

- 42,130
- 20
- 150
- 146
-
2This is a good solution but you should be comparing `as` (another prop on the callback object) to `router.asPath`, not `url`. The url maybe different even on the same page – nathajamal Nov 02 '21 at 16:35
-
1@nathajamal Yes, that's a good point. Since `asPath` is the path shown in the browser it only makes sense that it should be compared to the `as` prop. I've updated the answer. – juliomalves Nov 02 '21 at 16:57
-
-
3@SunnyPatel Because adding a listener to the `beforePopState` event of `next/router` should occur on the client-side. – juliomalves Mar 20 '22 at 14:05
-
1@juliomalves thank you for this! What if you wanted the useEffect to only run on back/foward and arriving at the page? This would be for the use case of syncing filter/sort/pagination state with the URL. – inthedark72 Aug 06 '22 at 23:37
-
-
@BryanLumbantobing Of course it does. What in this answer leads you to believe that it wouldn't? – maiorano84 Oct 27 '22 at 22:27
-
-
@milesmeow Setting the callback function to return true resets it to it's default behaviour. – juliomalves Feb 07 '23 at 01:35
-
When function detects browsers back action, how to prevent from going back while modal is opened? @juliomalves – Dejan Feb 23 '23 at 12:30
-
@Dejan Use `return false` in the condition where the modal is handled. – juliomalves Feb 23 '23 at 13:16
-
@juliomalves I've tried, it seems like it doesn't work, it should "disable" go back action if I return false in the condition where my modal is handled? Also I have another pitfall, when I click on browsers go back button, I got modal opened as expected but my url is changed immediately it should be the same until I confirm that action via modal. So point is to don't go back and don't change url until action is confirmed from modal. Any suggestion? – Dejan Feb 23 '23 at 13:47
-
You need the `return false` if the condition inside the `router.beforePopState` callback. – juliomalves Feb 23 '23 at 15:12
-
Fantastic answer by @juliomalves. However, we need to handle URLs properly. Once you return false from router.beforePopState
handler, page will not be updated. However, url is changed. And this is not what we want. So, it has to be copleted as per following code.
useEffect(() => {
router.beforePopState(({ as }) => {
const currentPath = router.asPath;
if (as !== currentPath) {
// Will run when leaving the current page; on back/forward actions
// Add your logic here, like toggling the modal state
// for example
if(confirm("Are you sure?") return true;
else {
window.history.pushState(null, "", currentPath);
return false;
}
}
return true;
});
return () => {
router.beforePopState(() => true);
};
}, [router]); // Add any state variables to dependencies array if needed.

- 16,027
- 10
- 55
- 122
-
This code really work .But How can I display Default Leave Prompt like Tiktok upload Page in Desktop Browser . Not confirm box but Leave Prompt . – ThanHtutZaw Jun 03 '23 at 07:36
@Summy I hope your issue is resolved by now. If not you can try this for the browser back button:- Next.js + React Go back to the previous page If you want to use hashbang URLs you can't use SSR, since /# and /#/one is the same route server-side, so there is no way for the server to know what to render, it will need to send a basic template and let the client fill it, in that case, I think using CRA or Parcel with React Router and its HashRouter is a better option, that way you will have a single index.html and let the client decide what to render.

- 585
- 12
- 34
in NextJs we can use beforePopState function and do what we want such close modal or show a modal or check the back address and decide what to do

- 638
- 7
- 9
I've tried above solution but unfortunately didn't work for me. I've managed to overcome given issues for following scenario: Open modal on browsers "go back" action. I had problem when I click on back button, I was getting opened modal but current url was changed to the previous url.
export default function BrowserGoBackAction() {
const [showGoBackDialog, setShowGoBackDialog] = useState(false);
const router = useRouter();
async function OpenGoBackDialog() {
setShowGoBackDialog(true);
}
useEffect(() => {
router.beforePopState(({ as }) => {
// Detect browsers go back action
if (as !== router.asPath) {
window.history.pushState(null, null, router.asPath);
OpenGoBackDialog();
}
});
});
function goToPreviousPage() {
router.beforePopState(() => true);
return router.back();
}
function onCancel() {
setShowGoBackDialog(false);
}
}

- 209
- 3
- 11
Any of the above solution is not working for my next js application.I found a different way to handle this issue although it is using the hash which will be a unique modalId and we will monitor the hash change via router.asPath and close the modal accordingly.
import { useEffect } from 'react';
import { useRouter } from 'next/router';
export const useRestrictModalNavigation = (
show: boolean,
onHashRemoved?: () => void
) => {
const router = useRouter();
const setModalHash = (modalId: string) => {
window.history.pushState({}, '', `#${modalId}`);
};
const handleClose = () => {
if (onHashRemoved) onHashRemoved();
clearModalHash();
};
useEffect(() => {
if (show) {
setModalHash('modal');
} else {
clearModalHash();
}
}, [show]);
useEffect(() => {
const handleHashChange = () => {
const { hash } = window.location;
console.log('Hash changed:', hash);
if (!hash) if (onHashRemoved) onHashRemoved();
};
window.addEventListener('hashchange', handleHashChange);
return () => {
window.removeEventListener('hashchange', handleHashChange);
};
}, [router.asPath]);
return { handleClose };
};
const clearModalHash = () => {
const { protocol, host, pathname, search } = window.location;
const newUrl = `${protocol}//${host}${pathname}${search}`;
window.history.replaceState({}, document.title, newUrl);
};

- 1
- 2