0
0
NextJSframework~5 mins

Modal pattern with intercepting routes in NextJS

Choose your learning style9 modes available
Introduction

Modals let you show extra info without leaving the page. URL query parameters help open modals while keeping the main page visible.

Showing details or forms without leaving the current page
Previewing images or content quickly without full page reload
Confirming actions like delete or save with a popup
Keeping the main page state while showing extra info
Improving user experience by avoiding full page navigation
Syntax
NextJS
import { useRouter, usePathname, useSearchParams } from 'next/navigation';
import { useState, useEffect } from 'react';

export default function Page() {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const [modalOpen, setModalOpen] = useState(false);

  useEffect(() => {
    const modalParam = searchParams.get('modal');
    setModalOpen(modalParam === 'true');
  }, [searchParams]);

  function openModal() {
    router.push(`${pathname}?modal=true`, { scroll: false });
  }

  function closeModal() {
    router.push(pathname, { scroll: false });
  }

  return (
    <>
      <main>
        <h1>Main Page Content</h1>
        <button onClick={openModal}>Open Modal</button>
      </main>
      {modalOpen && (
        <div role="dialog" aria-modal="true" aria-labelledby="modal-title" tabIndex={-1} className="modal">
          <h2 id="modal-title">Modal Content</h2>
          <p>This is a modal opened via URL query parameter.</p>
          <button onClick={closeModal}>Close Modal</button>
        </div>
      )}
    </>
  );
}

The modal state is controlled by a URL query parameter (e.g., ?modal=true).

Using router.push with scroll: false keeps the page position stable.

Examples
Opens the modal by adding a query parameter without scrolling the page.
NextJS
router.push(`${pathname}?modal=true`, { scroll: false });
Closes the modal by removing the query parameter and staying on the same page.
NextJS
router.push(pathname, { scroll: false });
Reads the URL to decide if the modal should be open or closed.
NextJS
const modalParam = searchParams.get('modal');
setModalOpen(modalParam === 'true');
Sample Program

This Next.js component shows a main page with a button. Clicking the button adds ?modal=true to the URL and opens a modal. Closing the modal removes the query parameter. The modal uses ARIA roles for accessibility and a semi-transparent background overlay.

NextJS
import { useRouter, usePathname, useSearchParams } from 'next/navigation';
import { useState, useEffect } from 'react';

export default function ModalPage() {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const [modalOpen, setModalOpen] = useState(false);

  useEffect(() => {
    const modalParam = searchParams.get('modal');
    setModalOpen(modalParam === 'true');
  }, [searchParams]);

  function openModal() {
    router.push(`${pathname}?modal=true`, { scroll: false });
  }

  function closeModal() {
    router.push(pathname, { scroll: false });
  }

  return (
    <>
      <main>
        <h1>Welcome to the Main Page</h1>
        <button onClick={openModal} aria-haspopup="dialog" aria-expanded={modalOpen}>Open Modal</button>
      </main>
      {modalOpen && (
        <div role="dialog" aria-modal="true" aria-labelledby="modal-title" tabIndex={-1} className="modal" style={{
          position: 'fixed',
          top: '50%',
          left: '50%',
          transform: 'translate(-50%, -50%)',
          backgroundColor: 'white',
          padding: '1rem',
          boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
          zIndex: 1000
        }}>
          <h2 id="modal-title">Modal Window</h2>
          <p>This modal opened using URL query parameters keeps the main page visible.</p>
          <button onClick={closeModal}>Close Modal</button>
        </div>
      )}
      {modalOpen && <div aria-hidden="true" style={{
        position: 'fixed',
        top: 0,
        left: 0,
        width: '100vw',
        height: '100vh',
        backgroundColor: 'rgba(0,0,0,0.3)',
        zIndex: 999
      }} />}
    </>
  );
}
OutputSuccess
Important Notes

Always use ARIA roles like role="dialog" and aria-modal="true" for accessibility.

Keep the background page visible but inert by using an overlay with aria-hidden="true".

Using the Next.js router with query parameters lets you change the URL without full page reload, improving user experience.

Summary

Modals with URL query parameters show popups without leaving the page.

Use URL query parameters to control modal open/close state.

Ensure accessibility with proper ARIA roles and keyboard focus management.