As React developers, we're always on the lookout for ways to elevate user experience. In this blog post, we'll explore a fascinating challenge: opening a modal when users click the browser's back button in a React application. While React Router v6 offers powerful navigation tools, addressing this specific scenario requires a unique approach.
Let's dive into the details! πβ¨
const [confirmModal, setConfirmModal] = useState(false)
First of all we are going to take a State for our Modal, so that we can render our modal.
<CustomModal
open={confirmModal}
onClose={closeModal}
containerStyle={{
width: "90%",
maxWidth: "380px",
minWidth: "380px",
height: "200px",
backgroundColor: "#F8F8F8",
}}
>
<div
style={{
display: "flex",
width: "100%",
justifyContent: "center",
alignItems: "center",
marginBottom: "20px",
}}
>
<p style={{ fontWeight: "600", fontSize: "16px" }}>
Confirm cancellation of this transaction?
</p>
</div>
<div className="flex justify-between">
<div>
<CustomButton title={"Yes"} onClick={leavePage} />
</div>
<div>
<CustomButton title={"No"} onClick={closeModal} />
</div>
</div>
</CustomModal>
We've implemented a straightforward modal, and you can also opt for a regular modal. In my case, I'm using a customModal.
Two functions are required initially to manage the modal. The first one is to close the modal:
const closeModal = () => {
setConfirmModal(false);
};
We will be using react-router-dom V6,
Initialise it with the following lines:
import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
We are just simply setting the state to false nothing much,
this function will be used when user clicks on the "YES" Button of our Modal.
const leavePage = () => {
navigate("/");
};
This function will either push the new URL onto the history stack or replace the current URL
const urlChangeHandler = (url, replace = false) => {
const historyMethod = replace ? "replaceState" : "pushState";
window.history[historyMethod];
};
Here we are using a arrow function where are making use of a window.history.replaceState method.
In simpler terms, the urlChangeHandler function is like a lookout for changes in the web address (URL). Whenever there's a change, it ensures our application stays updated with the new URL by either adding a new entry to the browser's history or replacing the current one. It's like keeping our app in harmony with what's happening in the browser's address bar.
Now's the time we bring in our javascript functions with useEffect Hook, we cannot use javascript native elements directly in react we need to use them inside the useEffect:
useEffect(() => {
urlChangeHandler(window.location.href);
enterValuesInHiddenInput();
return () => setConfirmModal(true);
}, []);
In this code snippet, we are using the urlChangeHandler function to handle the initial URL when the component mounts. We pass the current URL (window.location.href) to this function, effectively setting the URL without adding any extra state. This helps initialise the component's state based on the current URL.
We are calling one more function in the above useEffect, that is enterValuesHiddenInput(),
const hiddenInputRef = useRef(null);
const enterValuesInHiddenInput = () => {
hiddenInputRef.current.onclick;
};
<button
ref={hiddenInputRef}
style={{visibility: "hidden"}}>
Test
</button>
In the above code, we are making use of useRef hook, to run a onclick function to forcefully click the screen and then we are hiding this button.
Additionally, at our clean up function we are setting the state of our modal's state true.
The block of code will trigger the above events whenever user clicks on back button of browser
useEffect(() => {
enterValuesInHiddenInput();
const handlePopState = (event) => {
event.preventDefault();
setConfirmModal(true);
};
window.addEventListener("popstate", handlePopState);
window.history.pushState({ modalOpened: false }, "");
return () => {
window.removeEventListener("popstate", handlePopState);
};
}, [hiddenInputRef, urlChangeHandler]);
The popstate event listener in React is triggered when the browser's history navigation changes. It allows developers to respond to back and forward button clicks, enabling smooth navigation within the application.
In this code, we set up an event listener to detect when the user navigates in the browser. When that happens, we activate the handlePopState function, which sets the confirmModal state to true. This ensures the modal opens when the user interacts with the browser's navigation (e.g., clicks the back button). The cleanup function removes the event listener to prevent issues when the component unmounts.
Now, just call your modal inside
{confirmModal && (
<CustomModal
open={confirmModal}
onClose={closeModal}
containerStyle={{
width: "90%",
maxWidth: "380px",
minWidth: "380px",
height: "200px",
backgroundColor: "#F8F8F8",
}}
>
<div
style={{
display: "flex",
width: "100%",
justifyContent: "center",
alignItems: "center",
marginBottom: "20px",
}}
>
<p style={{ fontWeight: "600", fontSize: "16px" }}>
Are you sure you want to cancel this transaction?
</p>
</div>
<div className="flex justify-between">
<div>
<CustomButton title={"Yes"} onClick={leavePage} />
</div>
<div>
<CustomButton title={"No"} onClick={closeModal} />
</div>
</div>
</CustomModal>
)}
and with that it's done...
Here's the final Output
NOTE: before clicking on the browser back button user must interact with the ui first even as small as a click on a screen is enough...
Thank you for reading and Follow me on LinkedIn if youβre interested in Web Development. π
Top comments (2)
This is incredible! Thank you for the explanation. I learned a whole ton. :D
Thanks a lot also i am sorry that is working but i came across some browser issue when you navigate to the page where you want the modal to open on click of back button then first user needs to interact with the Ui even one click is enough then only the modal will open...