Skip to Content
BlogBuilding a Modal Route with React Router

Building a Modal Route with React Router

beautiful-bird

📸

Pexels

I don’t know about you, but I love modals. Specifically, when they’re used to display content without navigating away from the current page.

And today, I’ll show you how to create a modal route in React with the help of the react-router-dom library.

if some of you are not understanding what we are going to build, then you can see the stackblitz live demo example.

Use Case 🧐

  • Suppose you have a list of items and you want to show the details of the item in a modal and without navigating to a new page.
  • You want to show a form in a modal and submit the form without navigating to a new page.

Imagine how cool it would be to navigating to a new link without leaving the current page.

Okay enough talking, let’s start.

Getting Started 📌

I’m assuming you have a basic understanding of React and React Router. If not, I recommend checking out the official documentation. and also you have a basic react project setup.

Step 1 - Setup React Router

First, let’s set up the React Router in our project. We’ll be use the createBrowserRouter for define our routes.

App.js
import * as React from 'react' import { Dialog } from '@reach/dialog' import { createBrowserRouter, Link, Outlet, RouterProvider, useNavigate, useParams, } from 'react-router-dom' import '@reach/dialog/styles.css' import { getImageById, IMAGES } from './images' const router = createBrowserRouter([ { path: '/', Component: Layout, children: [ { path: '/', Component: Home, }, { path: 'gallery', Component: Gallery, children: [ { path: 'img/:id', Component: ImageView, }, ], }, ], }, ]) export default function App() { return <RouterProvider router={router} /> }

Step 2 - Create the Layout

The Layout component acts as the main structure of our application. It includes a navigation menu and an Outlet to render child routes.

Layout.js
export function Layout() { return ( <div> <h1>Outlet Modal Example</h1> <p> This is a modal example using `createBrowserRouter` that drives modal displays through URL segments. The modal is a child route of its parent and renders in the `Outlet`. </p> <div> <nav> <ul> <li> <Link to='/'>Home</Link> </li> <li> <Link to='/gallery'>Gallery</Link> </li> </ul> </nav> <hr /> </div> <Outlet /> </div> ) }

Now we have to create the Home Page.

Step 3 - Defining the Home Page

The Home page is the default route of our application. It contains a link to the Gallery route. It’s will be just a basic page with a link to the Gallery route.

Home.js
export function Home() { return ( <div> <h2>Home</h2> <p> Click over to the <Link to='/gallery'>Gallery</Link> route to see the modal in action. </p> <Outlet /> </div> ) }

The Gallery component displays a grid of images. Each image is a link that opens a modal by changing the URL to a child route.

Gallery.js
export function Gallery() { return ( <div style={{ padding: '0 24px' }}> <h2>Gallery</h2> <p> Click on an image to open a modal. You'll notice that the URL changes, and you still see this route behind the modal. The modal is a child route of <pre style={{ display: 'inline' }}>"/gallery"</pre>. </p> <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', gap: '24px', }} > {IMAGES.map((image) => ( <Link key={image.id} to={`img/${image.id}`}> <img width={200} height={200} style={{ width: '100%', aspectRatio: '1 / 1', height: 'auto', borderRadius: '8px', }} src={image.src} alt={image.title} /> </Link> ))} <Outlet /> </div> </div> ) }

And finally, we have to create the modal component to display the image.

Step 5 - The Modal Component

The ImageView component represents the modal itself. And for modal we gonna use the @reach/dialog package.

bash filename="terminal" copy npm install @reach/dialog

And here is the code for the ImageView component.

ImageView.js
export function ImageView() { let navigate = useNavigate(); let { id } = useParams<"id">(); let image = getImageById(Number(id)); let buttonRef = React.useRef<HTMLButtonElement>(null); function onDismiss() { navigate(-1); } if (!image) { throw new Error(`No image found with id: ${id}`); } return ( <Dialog aria-labelledby="label" onDismiss={onDismiss} initialFocusRef={buttonRef} > <div style={{ display: "grid", justifyContent: "center", padding: "8px 8px", }} > <h1 id="label" style={{ margin: 0 }}> {image.title} </h1> <img style={{ margin: "16px 0", borderRadius: "8px", width: "100%", height: "auto", }} width={400} height={400} src={image.src} alt="" /> <button style={{ display: "block" }} ref={buttonRef} onClick={onDismiss} > Close </button> </div> </Dialog> ); }

Woohoo! 🥳 You have successfully implemented the modal using @reach/dialog and react-router-dom.

Trust me, it’s a great feeling to create something like this. 🚀

Complete Code

If you need the complete code, you can find it here and find the live demo stackblitz here.

Thanks for reading! 🙌

Comments

Leave a comment or reaction below!

Last updated on