Next.js Modals Made Easy

Dan Tulpa
4 min readNov 10, 2023

--

A banner for a simple guide to Next.js 14 Modals

Next.js is well-known for being strong and flexible, but sometimes its documentation, particularly when it comes to parallel and partial routes, can make simple things seem a bit complicated. This article aims to make the process of adding modals in Next.js easier to understand, keeping it simple and clear!

The Stateless, Route-Based Approach

The Concept:

  • Stateless: This technique does not use useState or similar state management tools.
  • Route-Based: It uses URL search parameters to control the modal’s visibility.

How It Works

  1. Opening the Modal: The server component activates the modal when the URL includes the search parameter ?show=true
  2. Conditional Rendering: The page assesses the search parameters and then conditionally renders the Modal based on their presence.
  3. Dismissing the Modal: To close the modal, users have options:
  • Use the Link component to navigate back while maintaining the server-side nature.
  • Utilize useRouter for a more dynamic, client-side approach.

Implementing the Modal 🔨

Here’s a server component example that conditionally renders a modal based on URL search parameters:

import Link from "next/link";
import Modal from "@/components/Modal"

type SearchParamProps = {
searchParams: Record<string, string> | null | undefined;
};

export default function Page({ searchParams }: SearchParamProps) {
const show = searchParams?.show;

return (
<>
<Link href="/?show=true">
SUMMON THE MODAL
</Link>

{show && <Modal />}
</>
);
}
A simple Nextjs application with a styled button that will open a server component modal

When you click the button, ?show=true is added as a search parameter to the URL. This action triggers the conditional rendering of the modal, as the variable show becomes set to true.

A simple Next.js server side modal popup that renders based on the URL search params

Modal Visibility 👀

  • Opening the Modal: The modal appears when the URL includes:
    ?show=true.
  • Closing the Modal: To dismiss, users can either navigate back, use a specific close button, or remove the parameter from the URL.

Modal Component

Your modal component can be either a server component or a client component.

If you use Next’s <Link /> to dismiss the modal, it will remain a server component.

// Server-side Modal

function Modal() {

return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full flex items-center justify-center">
<div className="p-8 border w-96 shadow-lg rounded-md bg-white">
<div className="text-center">
<h3 className="text-2xl font-bold text-gray-900">Modal Title</h3>
<div className="mt-2 px-7 py-3">
<p className="text-lg text-gray-500">Modal Body</p>
</div>
<div className="flex justify-center mt-4">

{/* Navigates back to the base URL - closing the modal */}
<Link
href="/"
className="px-4 py-2 bg-blue-500 text-white text-base font-medium rounded-md shadow-sm hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-300"
>
Close
</Link>

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

If you need more flexibility, you have to use useRouterand ditch the server component in favor of a client component. Only the client component can use useRouter.

//Client-side modal

'use client'

import { useRouter } from "next/router";

function Modal() {
const router = useRouter()

return (
<div className="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full flex items-center justify-center">
<div className="p-8 border w-96 shadow-lg rounded-md bg-white">
<div className="text-center">
<h3 className="text-2xl font-bold text-gray-900">Modal Title</h3>
<div className="mt-2 px-7 py-3">
<p className="text-lg text-gray-500">Modal Body</p>
</div>
<div className="flex justify-center mt-4">

{/* Using useRouter to dismiss modal*/}
<button
onClick={router.back}
className="px-4 py-2 bg-blue-500 text-white text-base font-medium rounded-md shadow-sm hover:bg-gray-400 focus:outline-none focus:ring-2 focus:ring-gray-300"
>
Close
</button>

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

Advantages of This Approach ✅

  1. Simplicity: A simpler alternative to the more complex scenarios described in Next.js documentation.
  2. Stateless Design: Reduces complexity and boosts performance.
  3. Shareability: Enables direct link sharing to open modals.
  4. Performance: More efficient without the need for additional state management.

Conclusion

Implementing modals in Next.js doesn’t need to be overly complicated. By using a stateless, route-based approach, you can create efficient, user-friendly modals. This method is not only in line with modern web development practices but also simplifies the process, making it accessible for beginners and seasoned developers alike.

Thanks for reading, everyone. I hope this helps!

Happy hacking!

--

--

Dan Tulpa
Dan Tulpa

Written by Dan Tulpa

Software engineer based in Colorado. Passionate about technology, design, and personal development.