Back to Top

How to create a React Portal in Next Js?

Updated 30 May 2024

In this blog, we are going to explore the react portal and how can create the portal in NextJs. So first we’ll set up the NextJs App.

Understanding the react portal?

Basically, the React portal is a powerful technique to create a first-class way to render children into a DOM (Document object modal) Node from outside of their parent component hierarchy.

This means It provides the feature to render components outside of their parent component’s hierarchy. Which can be used for tooltips, alert modal boxes, and loaders.

You can see the image for the Portal example.

React portal Image example

The following are a few steps to create a react portal in Next js.

Start your headless eCommerce
now.
Find out More

Step 1: First We need to set up the Next Js App to implement in Next Js.

We will create the new file pages/_document. tsx in the root directory and you can see the final folder structure.

.
├── pages/
│   ├── api
│         ├── hello.ts
│   ├── app.tsx
|   ├──_documet.tsx
│   └── index.tsx
├── public/
│   ├── favicon.ico
│   ├── next.svg
│   └── vercel.svg
├── styles/
│   └── global.css
│   └── Home.module.css
├── next.config.js
├── package-lock.json
├── package.json
└── README.md

Step 2: Modify the _document.tsx file to mount the react portal.

_document. tsx file should exist in the page folder it is the file equivalent to the index.html file in react Js. So i created the div element with an id mount for my portal rendered inside the div element.

//pages/_document.tsx
import { poppins } from "@/components/ClientPortal";
import { Html, Head, Main, NextScript } from "next/document";


export default function Document() {
  return (
    <Html lang="en" className={poppins.className}>
      <Head />
      <body >
        <Main />
        <div id="myportal" />
        <NextScript />
      </body>
    </Html>
  );
}

Step 3: Create a ClientPortal.tsx file inside the components directory.

Note: It created the components/ClientPortal.tsx file in the root directory. and write the code to create a portal.

//components/ClientPortal.tsx

import { useEffect, useRef } from "react";
import { Poppins } from "next/font/google";
import { createPortal } from "react-dom";
type ClientPortalInterface = {
  children: React.ReactNode;
  show?: boolean;
  onClose?: () => void;
  selector: string;
};

const ClientPortal = ({ children, selector, show }: ClientPortalInterface) => {
  const ref = useRef<Element | null>(null);
  useEffect(() => {
    ref.current = document.getElementById(selector);
  }, [selector]);
  return show && ref.current ? createPortal(children, ref.current) : null;
};

export default ClientPortal;

export const poppins = Poppins({
  weight: ["400", "500", "600", "700"],
  subsets: ["latin"],
});

And apply some CSS to design the content.

//styles/Home.module.css
.main {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 6rem;
}

.removeButton{
  border: none;
  background-color: #ffffff;
  cursor: pointer;
  padding: 5px 7px;
}
.removeButton:hover{
  background-color: rgba(189, 195, 199, 1.0);
  border-radius: 6px;
}

/* Enable hover only on non-touch devices */
@media (hover: hover) and (pointer: fine) {
  .card:hover {
    background: rgba(var(--card-rgb), 0.1);
    border: 1px solid rgba(var(--card-border-rgb), 0.15);
  }

  .card:hover span {
    transform: translateX(4px);
  }
}

@media (prefers-reduced-motion) {
  .card:hover span {
    transform: none;
  }
}

.modal{
  background: rgba(255, 255, 255,1.0);
  width: 60%;
  max-height: 500px;
  border-radius: 15px;
  padding: 20px;
  z-index: 100;
}

.header{
  display: flex;
  align-items: center;
  justify-content: space-between; 
  border-bottom: 1px solid rgba(189, 195, 199,1.0);
}
.header h4{
  color: rgb(17 24 39 0.3);
  font-size: 20px;
  font-weight: 600;
  margin-bottom: 13px;
}

.body{
  padding-top: 10px;
}
.body p{
  color: rgba(116, 125, 140,1.0);
  font-size: 14px;
  line-height: 28px;
  text-align: left;
}
.overflow{
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: rgba(0, 0, 0, 0.4);
  transition: 1;
}

.btn {
  padding: 8px 18px;
  cursor: pointer;
  border: 0px solid rgb(14, 158, 62);
  border-radius: 3px;
  color: rgba(255, 255, 255,1.0);
  font-size: 16px;
  border-radius: 5px;
  background: rgb(14, 158, 62);  
}
.btn:hover{
  background: rgb(9, 99, 39); 
}

.groupbtn{
  display: flex;
  justify-content: flex-end;
}
.cancleBtn{
  padding: 10px 20px;
  margin: 0px 10px;
  cursor: pointer;
  border: 0px solid rgba(231, 76, 60,1.0);
  border-radius: 3px;
  color: rgba(255, 255, 255,1.0);
  font-size: 16px;
  border-radius: 5px;
  background: rgba(231, 76, 60,1.0); 
}
.reactontent {
  margin: 20px 0px;
}

Step 4: Import the ClientPortal component in the pages/index.tsx file in the root directory.

//pages/index.tsx
import { useState } from "react";
import styles from "@/styles/Home.module.css";
import ClientPortal from "../components/ClientPortal";
export default function Home() {
  const [showPortal, setShowPortal] = useState(false);
  const handleModal = () => {
    setShowPortal(!showPortal);
  };
  

  return (
    <>
      <main className={`${styles.main}`}>
        <h1>Implementation portal in next JS</h1>
        <button onClick={handleModal} className={styles.btn}>
          Read Blog
        </button>
      </main>
      <ClientPortal
        selector="myportal"
        show={showPortal}
      >
        <div className={styles.overflow}>
          <div className={styles.modal}>
            <div className={styles.header}>
              <h4>Lorem Ipsum</h4>
              <button onClick={handleModal} className={styles.removeButton}>
              {/* <button className={styles.removeButton}> */}
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  height="1em"
                  viewBox="0 0 384 512"
                >
                  <path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z" />
                </svg>
              </button>
            </div>
            <div className={styles.body}>
              <p>
                Basically, React Portal is a powerful technique to create a
                first-class way to render children into a DOM (Document object
                modal) Node from outside of their parent component hierarchy.
              </p>
              <div className={styles.reactontent}>
                <h4>Industry's stand 1960s with the release</h4>
                <p>
                  has been the industry's stand 1960s with the release of
                  Letraset sheets containing Lorem Ipsum passages, and more
                  recently with desktop publishing software like Aldus PageMaker
                  including versions of Lorem Ipsum.
                </p>
              </div>
              <div className={styles.reactontent}>
                <p>
                  Lorem Ipsum is simply dummy text of the printing It has
                  survived not only five centuries, but also the leap into
                  electronic typesetting, remaining essentially unchanged. It
                  was popularised in the 1960s with the release of Letraset
                  sheets containing Lorem Ipsum passages, and more recently
                </p>
              </div>
              <div className={styles.reactontent}>
                <p>
                  Lorem Ipsum is simply dummy text of the printing and
                  typesetting industry. Lorem Ipsum has been the industry's
                  standard dummy text ever since the 1500s, when an unknown
                  printer took a galley of type and Lorem Ipsum.
                </p>
              </div>
            </div>
          </div>
        </div>
      </ClientPortal>
    </>
  );
}

You can see the result on localhost.

React Modal Box button

Start your Headless Development with Webkul.

Happy Coding!!

. . .

Leave a Comment

Your email address will not be published. Required fields are marked*


Be the first to comment.

Back to Top

Message Sent!

If you have more details or questions, you can reply to the received confirmation email.

Back to Home