Skip to Content
BlogHow to Create a Modal Route in Next.js.

Create a Modal Route in Next.js

Modal

πŸ“Έ

Pexels

In my previous article, I showed you how to create a modal route in React. Today, I’ll show you how to create a modal route in Next.js using Parallel Routes  and Intercepting Routes .

In case you missed the previous article, you can find it here.

So few days ago i was working on a project where i need to create a modal route in Next.js, and i was thinking how can i create a modal route in Next.js, so i started searching on google and i found a solution to create a modal route in Next.js using Parallel Routes and Intercepting Routes. And trust me you will fall in love with next modal once you will learn to create it.

This allows you to solve common challenges when building modals, such as:

  • Making the modal content shareable through a URL.
  • Preserving context when the page is refreshed, instead of closing the modal.
  • Closing the modal on backwards navigation rather than going to the previous route.
  • Reopening the modal on forwards navigation.

Getting Started πŸ“Œ

Let’s create a simple example of a product listing page with a modal for product details. We’ll use Parallel Routes for the modal and Intercepting Routes for deep linking.

Folder Structure πŸ“

But first understand it’s folder structure because after all next.js is all about folder and files.

app/ β”œβ”€β”€ layout.tsx β”œβ”€β”€ page.tsx β”œβ”€β”€ products/ β”‚ └── [id]/ β”‚ └── page.tsx └── @modal/ β”œβ”€β”€ default.tsx └── (.)products/ └── [id]/ └── page.tsx

Okay now first start from the layout.tsx file.

Step 1 - Change the layout.tsx file

layout.tsx
import Link from 'next/link' export default function RootLayout({ children, modal }: { children: React.ReactNode modal: React.ReactNode }) { return ( <html lang="en"> <body> <header> <nav> <Link href="/">Home</Link> </nav> </header> <main>{children}</main> {modal} </body> </html> ) }
πŸ‘Ύ

Watch out for the modal prop in the RootLayout component. Otherwise the modal won’t be rendered. And you will pull your hair out like me.🀭

Step 2 - Home page with product listing

app/page.tsx
import Image from "next/image" import Link from "next/link" import { products, type Product } from "@/app/data/products" export default function Home() { return ( <div className="min-h-screen bg-gray-100 py-12 px-4 sm:px-6 lg:px-8"> <div className="max-w-7xl mx-auto"> <h1 className="text-4xl font-extrabold text-center text-gray-900 mb-10"> Luxury Products </h1> <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8"> {products.map((product: Product) => ( <Link key={product.id} href={`/products/${product.id}`} className="group" > <div className="bg-white rounded-lg shadow-md overflow-hidden transition-transform duration-300 ease-in-out transform hover:scale-105"> <div className="relative h-64 w-full"> <Image src={product.image} alt={product.name} layout="fill" objectFit="cover" className="transition-opacity duration-300 group-hover:opacity-75" /> </div> <div className="p-4"> <h2 className="text-xl font-semibold text-gray-800 mb-2"> {product.name} </h2> <p className="text-sm text-gray-600">Click to view details</p> </div> </div> </Link> ))} </div> </div> </div> ) }

Now we will create the dynamic product page.

Step 3 - Product details page

So we need to create the product details page so that if the user refresh the page then the dynamic product details page should be there. So let’s create the dynamic product details page.

app/products/[id]/page.tsx
import Image from "next/image" import Link from "next/link" import { products, type Product } from "@/app/data/products" export default function ProductPage({ params }: { params: { id: string } }) { const product = products.find((p) => p.id === parseInt(params.id)) if (!product) { return <div>Product not found</div> } return ( <div className="min-h-screen bg-gray-100 py-12 px-4 sm:px-6 lg:px-8"> <div className="max-w-4xl mx-auto bg-white rounded-lg shadow-md overflow-hidden"> <div className="md:flex"> <div className="md:flex-shrink-0"> <div className="relative h-96 w-full md:w-96"> <Image src={product.image} alt={product.name} layout="fill" objectFit="cover" /> </div> </div> <div className="p-8"> <h1 className="text-3xl font-bold text-gray-800 mb-4"> {product.name} </h1> <Link href="/" className="inline-block px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 transition-colors duration-300" > Back to Products </Link> </div> </div> </div> </div> ) }

Now we gonna create the folder called @modal and inside that folder we will create a file called default.tsx. default.js file that returns null. This ensures that the modal is not rendered when it’s not active.

Step 4 - Create the default modal

@modal/default.tsx
export default function Default() { return null }

So now we will create the modal for the product details page.

Step 5 - Create the product details modal

@modal/(.)products/[id]/page.tsx
"use client" import Image from "next/image" import Modal from "@/components/modal" import { products } from "@/app/data/products" export default function ProductModal({ params }: { params: { id: string } }) { const product = products.find((p) => p.id === parseInt(params.id)) if (!product) { return null } return ( <Modal> <div className="flex"> <div className="w-1/2 relative h-96"> <Image src={product.image} alt={product.name} layout="fill" objectFit="cover" /> </div> <div className="w-1/2 p-6"> <h2 className="text-3xl font-bold text-gray-800 mb-4"> {product.name} </h2> </div> </div> </Modal> ) }

And that’s it! I think now your modal route should work perfectly. If you are still facing any issue then you can check the code on GitHub  clone it and try to understand. If you want to learn more about it you can check the Nextjs Modal . Also you can check the live demo .

Thanks I think i should sleep now.😴

Bye Bye!πŸ‘‹

Comments

Leave a comment or reaction below!

Last updated on