javascriptnext.jsnext.js13react-server-componentsapp-router

Parallel route modal using Next.js 13's App Router returns 404 on refresh


I'm trying building modal using parallel routes in Next.js 13.4.

It works when I'm on the homepage (/) and open the modal (push to /login).

But when I refresh the /login page, instead of showing homepage with modal, it shows the 404 page with the modal:

404 not found with modal above

This is my folder structure:

Project folder structure

This is @overlays/login/page.tsx:

'use client';

import {useRouter} from 'next/navigation';
import {Dialog} from '@mui/material';

export default function Page() {
    const router = useRouter();

    return (
       <Dialog
          open
          onClose={router.back}
          keepMounted
          disablePortal
       >
          Hello
       </Dialog>
    );
}

Could you tell me how to render the home page (/) when navigating directly on parallel route /login?


Solution

  • In order to get rid of the 404, you are probably missing @overlays/default.tsx:

    export default function Default() {
      return null;
    };
    

    It's explained in the docs for Parallel Routes > Unmatched Routes:

    Unmatched Routes

    By default, the content rendered within a slot will match the current URL.

    In the case of an unmatched slot, the content that Next.js renders differs based on the routing technique and folder structure.

    [...]

    Reload

    On reload, Next.js will first try to render the unmatched slot's default.js file. If that's not available, a 404 gets rendered.

    Based on your last question, it looks like you don't want the modal to be accessible as a standalone page, which is what the documentation seems to consider one of the main use cases for this:

    Other examples could include opening a login modal in a top navbar while also having a dedicated /login page, or opening a shopping cart in a side modal.

    If you want /login to redirect to / when directly accessed, your might want to use router interception to render a different component in that case, which can then just call redirect('/'), so you should end up with the following files:

    app
      (home)
      login
        page.tsx <= LoginPage
      @overlays
        login
          page.tsx <= LoginModal
        page.tsx
    

    And login/page.tsx looks something like this:

    import { redirect } from 'next/navigation'
    
    export default function LoginPage() {
      redirect('/')
    
      return null;
    };