Skip to content

etienne-martin/react-portal-hook

Repository files navigation

react-portal-hook

A small React portal library made with hooks. Allows you to render an indefinite number of portals without having to define them in advance. Useful for event-driven notifications or modals where you don't know how many items will be rendered at a given time.

Getting Started

Installation

To use react-portal-hook in your project, run:

npm install react-portal-hook

Setup

Wrap your root component with PortalProvider.

// app.jsx

import { PortalProvider } from "react-portal-hook";

const App = () => {
  return (
    <PortalProvider>
      <RootComponent />
    </PortalProvider>
  );
};

Usage

Example - Modals:

By default, portals will be appended to document.body.

Demo

// page.jsx

import { usePortals } from "react-portal-hook";

const Modal = ({ closeModal }) => {
  return (
    <div>
      <h2>Title</h2>
      <p>This is a modal</p>
      <button onClick={closeModal}>Close Modal</button>
    </div>
  );
};

export const Page = () => {
  const portalManager = usePortals();

  const openModal = () => {
    portalManager.open(portal => <Modal closeModal={portal.close} />);
  };

  return (
    <div>
      <h2>Title</h2>
      <p>This is a page</p>
      <button onClick={openModal}>Open Modal</button>
    </div>
  );
};

Example - Notifications:

You can specify a DOM node in which to render portals with the appendTo option:

Demo

// layout.jsx

import { useRef } from "react";
import { usePortals } from "react-portal-hook";

const Notification = ({ closeNotification }) => {
  return (
    <div>
      <p>
        This is a notification{" "}
        <button onClick={closeNotification}>Close Notification</button>
      </p>
    </div>
  );
};

export const Layout = () => {
  const portalManager = usePortals();
  const notificationEl = useRef();

  const showNotification = () => {
    // Calling this from anywhere in your app will render a notification
    portalManager.open(
      portal => <Notification closeNotification={portal.close} />,
      {
        appendTo: notificationEl.current
      }
    );
  };

  return (
    <div>
      <div id="notification-holder" ref={notificationEl} />
      <button onClick={showNotification}>Show Notification</button>
    </div>
  );
};

API Documentation

portalManager

interface PortalManager {
  /**
   * The react element you want to render in the portal
   */
  element: ((portal: Portal) => React.ReactElement) | React.ReactElement;
  options?: {
    /**
    * An ID to avoid duplicate portals
    */
    id?: string;
    /**
    * A DOM node in which to render the portal
    */
    appendTo?: Element;
    /**
    * A callback that is fired when the portal closes
    */
    onClose?: () => void;
  };
}

Portal

interface Portal {
  /**
  * A function to close the Portal
  */
  close: () => void;
}

About

A small react portal library made with hooks

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published