usePortal React hook

Casper Iversen April 04, 2021

A simple React hook for creating portals for next.js!

import * as React from "react";

export function usePortal(id = "unknown") {
  // the ref that is going to be returned.
  const ref = React.useRef<HTMLDivElement>(null);

  React.useEffect(() => {
    // The element that will be created onMount and removed on unMount.
    let element: HTMLDivElement | null = null;

    if (!ref.current) {
      element = document.createElement("div");

      // You can give a it custom id.
      element.setAttribute("id", `Modal_Portal_${id}`);

      // Add the element to the "body", this can also be any other element.
      document.body.appendChild(element);

      ref.current = element;
    }

    return () => {
      // on unMount remove the element from the DOM
      ref.current = null;
      document.body.removeChild(element);
    };
  }, [id]);

  // return the ref so it can be used
  return ref.current;
}
import * as React from "react";
import ReactDOM from "react-dom";

export const MyCoolModal = () => {
  const [isOpen, setOpen] = React.useState(false);
  // use the ref and add a custom Id
  const portalRef = usePortal("my-cool-modal");

  return (
    <div>
      <button onClick={() => setOpen(true)}>Open modal</button>

      {isOpen
        ? // Use react-dom to create a portal
          portalRef &&
          ReactDOM.createPortal(
            <div style={{ width: "100%" }}>
              <h1>Hello from the modal!</h1>

              <button onClick={() => setOpen(false)}>Close modal</button>
            </div>,
            // set the portal element to the portalRef
            portalRef,
          )
        : null}
    </div>
  );
};

Try it out yourself here 🚀

You can now also use this hook via npm/yarn by installing my npm package:

npm install @casper124578/useful

Later in your project

import { usePortal } from "@casper124578/useful/hooks/usePortal";