JavaScript, Software Development

Enhancing UX in React: How to Close MUI Modals with the Browser Back Button

Modern web applications often use modal dialogs as a way to provide additional user interfaces without navigating away from the current view. One of the most popular libraries for React developers is Material-UI (MUI), which provides a rich set of components, including modal dialogs.

However, a common usability problem with modals is that users might expect to close them using the browser’s back button, but this doesn’t work by default. In this post, we’ll explore a method to handle this behavior using React, MUI, and TypeScript.

Prerequisites:

  • A React application bootstrapped with TypeScript (e.g., using Create React App with the TypeScript template).
  • Installed @mui/material library for the MUI components.
  • Familiarity with React hooks and React Router (if your application uses routing).

Step-by-step Guide:

Add a Modal Component: For demonstration purposes, let’s assume we have a simple MUI Modal:

import Modal from '@mui/material/Modal';
// ... other imports

const MyModal: React.FC = () => {
  const [open, setOpen] = React.useState(false);

  return (
    <>
      <Button onClick={() => setOpen(true)}>Open Modal</Button>
      <Modal open={open} onClose={() => setOpen(false)}>
        <div>Modal Content Here</div>
      </Modal>
    </>
  );
}

Add Routing (if not already present): Let’s assume you are using react-router-dom for routing. We will use its features to manage our back button behavior.

    Install it using (this example uses v6):

    npm install react-router-dom @types/react-router-dom
    

    Using the useHistory Hook: Import and utilize the useHistory hook from react-router-dom.

    import { useNavigate, useLocation } from 'react-router-dom';

    Within your component:

      const navigate = useNavigate(); 
      const location = useLocation(); 

    Modify the Modal Open/Close logic:

    When the modal is opened, push a new entry to the history. When it’s closed, use the goBack function.

        const handleOpen = () => {
            setOpen(true);
            navigate('#modal'); // Use navigate for changing routes
        };
    
        const handleClose = () => {
            setOpen(false);
            if (location.hash === '#modal') {
                navigate(-1); // This replaces history.goBack()
            }
        };
    

    React to the Back Button:

    Now, to close the modal when the back button is pressed, listen to the history changes and close the modal when the hash is not #modal.

        React.useEffect(() => {
            if (location.hash !== '#modal') {
                setOpen(false);
            }
        }, [location]);
    

    Putting it All Together:

    import React from 'react';
    import Modal from '@mui/material/Modal';
    import { Button } from '@mui/material';
    import { useNavigate, useLocation } from 'react-router-dom';
    
    const MyModal: React.FC = () => {
        const [open, setOpen] = React.useState(false);
        const navigate = useNavigate(); 
        const location = useLocation(); 
    
        const handleOpen = () => {
            setOpen(true);
            navigate('#modal');
        };
    
        const handleClose = () => {
            setOpen(false);
            if (location.hash === '#modal') {
                navigate(-1); 
            }
        };
    
        React.useEffect(() => {
            if (location.hash !== '#modal') {
                setOpen(false);
            }
        }, [location]);
    
        return (
            <>
                <Button onClick={handleOpen}>Open Modal</Button>
                <Modal open={open} onClose={handleClose}>
                    <div>Modal Content Here</div>
                </Modal>
            </>
        );
    }
    
    export default MyModal;

    Remember to add the Router context, example:

    import './App.css';
    import MyModal from './MyModal';
    import { BrowserRouter as Router } from 'react-router-dom';
    
    function App() {
      return (
        <Router>
          <div className="App">
            <MyModal />
          </div>
        </Router>
      );
    }
    
    export default App;

    Enhancing the user experience by aligning with common user expectations is vital. With the steps above, you can easily enable your MUI modal to close when the user presses the back button in a React.js application with TypeScript. Remember always to test your changes across different browsers to ensure consistent behavior.