Next.js Server-Side Modals Made Easy

Next.js Server-Side Modals Made Easy

Author

Dan Tulpa

Server-side Modals in Next.js: A Simplified Approach

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

Opening the Modal: The server component activates the modal when the URL includes the search parameter ?show=true. More on this later!

Conditional Rendering: The page assesses the search parameters and then conditionally renders the Modal based on their presence.

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:

// page.tsx
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 />}
    </>
  );
}

The above code is rendering in a <Link> button with the text SUMMON THE MODAL. There is also a Logical AND (&&) statement that is controlling when the <Modal/> Component will be rendered.

Image

When you click the button (our <Link> tag), ?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.

Button Clicked

Image

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 useRouter and 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

  • Simplicity: A simpler alternative to the more complex scenarios described in Next.js documentation.
  • Stateless Design: Reduces complexity and boosts performance.
  • Shareability: Enables direct link sharing to open modals.
  • 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!

Keep hacking,

Dan

Share