4

I wanted to create a Modal in NextJS 13.4 (with the new layout.tsx file system), But I couldn't. since this is a new thing I couldn't find a solution on the web either.

Here are the things that I've tried:

Edit:

  1. In the solutions:
import React from "react";
import { createPortal } from "react-dom";

const Modal = () => {
    return createPortal(
        <React.Fragment>
            <div>your content</div>
        </React.Fragment>,
        Document.body as HTMLElement
    );
};

export default Modal;

It will throw:

document is not defined

Tried to import Document from 'next/document' but still not working.

Another Error was error Error: createPortal was called on the server. Portals are not currently supported on the server. Update your program to conditionally call createPortal on the client only.

I've added "use client" on the first line and it will solve that error.

But still no results in showing that modal content.

  1. How to create a portal in Next Js

Since the step 1 of this tutorial is telling to create a _document file and place your portal element with a specific ID there, I did this in Layout.tsx (I think its the same as document file).

layout.tsx codes

Resulted in: Hydration Error

  1. Other tutorials also resulted the same...

Please provide a valid answer. I know how to create a portal in react or previous versions of next. This is a new version that has been changed insignificantly.

Re9iNee
  • 412
  • 5
  • 15

3 Answers3

5
  1. Declare your Modal as a client component by adding the "use client" annotation

  2. Render its children only when the component has mounted on the client.

"use client";

import * as React from "react";
import { createPortal } from "react-dom";

export default function Modal({ children }: React.PropsWithChildren) {
  const [mounted, setMounted] = React.useState(false);

  React.useEffect(() => setMounted(true), []);

  return mounted ? createPortal(<>{children}</>, document.body) : null;
}
Igor Danchenko
  • 1,980
  • 1
  • 3
  • 13
0

This solution is cool for a simple app, but how do you do when you have Providers / Navbar / Footer already nested in the body element? Here's an example as I can't manage to make it work properly, it keeps being generated outside of the body element:

  export default function RootLayout({ children }) {

  return (
    <html lang="en">
      <body className={playfairDisplay.className}>
        <Providers>
          <PolyNav />
          <div id="content-container" style={{ marginTop: "5.5rem" }}>
            {children}
          </div>
          <Footer />
        </Providers>
      </body>
    </html>
  );
}

enter image description here

Sunamin34
  • 174
  • 1
  • 7
-1

you can use react-dom create portal

    import React from "react";
    import { createPortal } from "react-dom";

export interface ModalProps {
  open: boolean;
  onClose: () => void;
  
}

const Modal: React.FC<ModalProps> = ({ open, onClose }) => {
  

  if (!open) return null;

  return createPortal(
    <React.Fragment>
      <div>
        your content
      </div>
    </React.Fragment>,
    document.body as HTMLElement
  );
};

export default Modal;