DEV Community

Cover image for How to Implement Modal using React Router v6
Roselle Tabuena
Roselle Tabuena

Posted on • Updated on

How to Implement Modal using React Router v6

Hello! I've been searching how to implement Modal in React Router v6, but unfortunately, the results that I found didn't match my needs. The tutorial blogs that I came across were using JSX Routes and I'm using createBrowserRouter to manage my history stack. After some searching and trying to make it work, I finally got it to work. 🙃

react-router-modal-sample-v5

If you want to achieve the sample GIF above but in React V6 and you're using createBrowserRouter, then this tutorial is for you ✨

Here's how I did it. 😄

react-router-modal-sample

The tutorial below will be just focusing on implementing modal it doesn't have navbar like in the image above.

START

First things first, You need to create react app and install the react-router-dom and run npm install to start.

Let's start with the folder structure. Simply copy the layout of my files and folders provided below:

/src
  /components
   Modal.js
  /data
   dummy-data.js
  /pages
   Gallery.jsx
  App.jsx
Enter fullscreen mode Exit fullscreen mode

dummy-data.js

export const images = [
  {
    id: 1,
    thumbnail:
      'https://images.unsplash.com/photo-1682685797886-79020b7462a4?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxlZGl0b3JpYWwtZmVlZHwxfHx8ZW58MHx8fHx8',
    fullSize:
      'https://images.unsplash.com/photo-1682685797886-79020b7462a4?q=80&w=2070&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
    details: 'Details about Image 1',
  },
  {
    id: 2,
    fullSize:
      'https://images.unsplash.com/photo-1706028024882-0b972506d02d?q=80&w=1964&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
    thumbnail:
      'https://images.unsplash.com/photo-1706028024882-0b972506d02d?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzfHx8ZW58MHx8fHx8',
    details: 'Details about Image 2',
  },
];

Enter fullscreen mode Exit fullscreen mode

dummy-data.jscontains a array object that will be use as our dummy data. The id will be a unique identifier for our image it will be use later to get the image details.

Modal.jsx

import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { images } from '../data/dummy-data';

const Modal = () => {
  const { id: imageId } = useParams();
  const navigate = useNavigate();

  const [imageData, setImageData] = useState(null);

  useEffect(() => {
    const image = images.find(({ id }) => imageId == id);

    setImageData(image);
  }, [imageId]);

  const handleOnClose = () => {
    navigate('/');
  };

  return (
    <>
      {imageData && (
        <div className="modal">
          <div className="modal-content">
            <img src={imageData.fullSize} alt="Full Size" />
            <p>{imageData.details}</p>
            <button onClick={handleOnClose}>Close</button>
          </div>
        </div>
      )}
    </>
  );
};

export default Modal;
Enter fullscreen mode Exit fullscreen mode

Modal.jsx is a functional component will be used to as our pop up modal for viewing details of specific image.

Variable Declarations:

imageId: extracts the id from the route using useParams() This is the unique identifier for the image being displayed in the modal.

navigate Provides a function to navigate between pages using useNavigate().

State Management:

imageData represents the state for holding information about the selected image.

useEffect is used to fetch the details of the image when the component mounts or when the imageId changes. It finds the corresponsing image in the images array object (imported from the dummy-data).

Close Modal Function:

handleOnClose defines a function to clode the modal by navigating back to the root path ('/) using the navigatefunction.

Render Modal:

The component renders a modal only if imageData is truthy (i.e., an image is found). Inside the modal, it displays the full-size image, additional details, and close button.

Gallery.jsx

import React from 'react';
import { useNavigate } from 'react-router-dom';
import { images } from '../data/dummy-data';
import Modal from '../components/Modal';

const Gallery = () => {
  const navigate = useNavigate();

  const viewImage = (image) => {
    const id = image.id;
    navigate('/view/' + id);
  };

  return (
    <div className="gallery">
      {images.map((image, index) => (
        <button
          key={image.id}
          className="gallery-item"
          onClick={() => viewImage(image)}
        >
          <img src={image.thumbnail} alt={`Thumbnail ${index + 1}`} />
        </button>
      ))}

      <Modal />
    </div>
  );
};

export default Gallery;

Enter fullscreen mode Exit fullscreen mode

Gallery.jsx is responsible for rendering a gallery of images with thumbnail previews. Inside the component, it maps over the images array object from dummy data. Each button has a click event handler (onClick) that calls the viewImage function with the corresponding image.

The viewImage function takes an image object parameter based on the thumbnail click, and it extracts the id property from the image object. It then navigates to the route view/:id.

The Modal component is rendered at the end of the Gallery component. It is included to provide the modal functionality for viewing detailed information about a selected image.

App.jsx

import React from 'react';
import Gallery from './pages/gallery';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

const router = createBrowserRouter([
  {
    path: '/',
    element: <Gallery />,
    children: [
      {
        path: 'view/:id',
        element: null,
      },
    ],
  },
]);

function App() {
  return (
    <React.StrictMode>
      <RouterProvider router={router} />
    </React.StrictMode>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

createBrowserRouter is the recommended router for all React Router web projects. It uses DOM History API to update the URL and manage the history stack.

The main router for the code above is specified with path: '/' and is set to render the Gallerycomponent.

Additionally, there's a child route defines with path: 'view/:id' but the element associated with it is set to null.

The RouterProvider component is used to provide the router instance (router) to the entire React component tree. This is crucial for enabling the routing functionality.

react-router-modal-sample

End of Code.


Explanation Summary:

We have an index parent route and it has children route view/:id that renders null element. If we navigate to this routes, the parent element will retain its current position. The reason for this is that we don't have an <Outlet /> to render the children of the parent route. So, it will just stay at the location where we trigger the navigation. The reason why the Modal is showing because we have a useEffect that triggers when the gallery/:id changes. It will only trigger if we click the thumbnails that triggers to update the URL.

That's all! I hope this was helpful. If you have any questions, feel free to ask. Thanks for reading!

LIVE DEMO
Source Code With Navbar
Source Code Modal Only

Top comments (4)

Collapse
 
esla profile image
Kartikey Shukla

Thanks for the article, but it won't work when you directly go to path /view/1.

Collapse
 
iamdete profile image
Roselle Tabuena

Hello, thank you for pointing that out. It's already working. the cause of the bug is because Netlify doesn't have an idea of where to locate the path on the server side. I just added a netlify.toml in the root and included this code:

[[redirects]]
from = "/*"
to = "/index.html"
status = 200
Enter fullscreen mode Exit fullscreen mode

I use this referrence to fix the bug medium.com/@iamtonmoy0/netlify-rea...

Thank you!

Collapse
 
ferlaxi profile image
Fernando Laxi

Very good article, I have a question, if I don't put a gallery and put a button that redirects to a component in the form of a modal, will it be possible?

Collapse
 
iamdete profile image
Roselle Tabuena

Hello Laxi, do you mean remove the navigation but still display the modal? Or do you mean to use other element that will display the modal?

I'll try to answer your question based on my understanding. Another way to display the modal is by relying on the search parameters. It's much easier to depend on them rather than on the URL path.

It's also possible to use other HTML elements like links, buttons, etc., to display our modal.

Could you provide more details about your question so that I can answer it properly?