or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-react-portal

React library that simplifies working with React Portals by providing Portal and PortalWithState components for breaking out of normal DOM hierarchy.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/react-portal@4.3.x

To install, run

npx @tessl/cli install tessl/npm-react-portal@4.3.0

index.mddocs/

React Portal

React Portal is a React library that simplifies working with React Portals by providing two main components: Portal and PortalWithState. The Portal component transports children into a new React Portal (typically appended to document.body) and supports targeting custom DOM elements, server-side rendering, and returning arrays without wrapper divs. The PortalWithState component adds convenience by managing its own state and providing features like close-on-ESC, close-on-outside-click, and callback functions for open/close events.

Package Information

  • Package Name: react-portal
  • Package Type: npm
  • Language: JavaScript (React)
  • Installation: npm install react-portal or yarn add react-portal

Core Imports

import { Portal, PortalWithState } from 'react-portal';

For CommonJS:

const { Portal, PortalWithState } = require('react-portal');

Basic Usage

import React from 'react';
import { Portal, PortalWithState } from 'react-portal';

// Basic Portal usage
const MyModal = ({ isOpen, children }) => (
  isOpen && <Portal>{children}</Portal>
);

// PortalWithState usage with built-in controls
const AdvancedModal = () => (
  <PortalWithState closeOnOutsideClick closeOnEsc>
    {({ openPortal, closePortal, isOpen, portal }) => (
      <React.Fragment>
        <button onClick={openPortal}>Open Modal</button>
        {portal(
          <div style={{ background: 'white', padding: '20px' }}>
            <h2>Modal Content</h2>
            <button onClick={closePortal}>Close</button>
          </div>
        )}
      </React.Fragment>
    )}
  </PortalWithState>
);

Architecture

React Portal is built around React's Portal API with the following key components:

  • Portal Component: Core portal functionality with automatic React version compatibility (16+ vs 15)
  • PortalWithState Component: Stateful wrapper providing built-in open/close management
  • Compatibility Layer: Automatic fallback between modern ReactDOM.createPortal and legacy unstable_renderSubtreeIntoContainer
  • Event Management: Built-in ESC key and outside click handling for modals and popups
  • SSR Support: Server-side rendering compatibility through DOM environment detection

Capabilities

Basic Portal Creation

Core portal component that transports React elements into a React Portal, breaking out of normal DOM hierarchy for proper styling and positioning.

/**
 * Portal component that renders children into a React Portal
 */
class Portal extends React.Component<PortalProps> {}

interface PortalProps {
  /** React elements to be portaled */
  children: React.ReactNode;
  /** Optional target DOM element (defaults to auto-created div in document.body) */
  node?: HTMLElement | Element | null;
}

Usage Examples:

// Portal to document.body (default)
<Portal>
  <div>This content appears at the end of document.body</div>
</Portal>

// Portal to custom element
const customTarget = document.getElementById('modal-root');
<Portal node={customTarget}>
  <div>This content appears in the custom element</div>
</Portal>

// Conditional portal
{isModalOpen && (
  <Portal>
    <div className="modal-overlay">
      <div className="modal-content">Modal content here</div>
    </div>
  </Portal>
)}

Stateful Portal Management

Advanced portal component with built-in state management, event handling, and render prop pattern for complete portal control.

/**
 * Stateful portal component using render prop pattern
 */
class PortalWithState extends React.Component<PortalWithStateProps> {}

interface PortalWithStateProps {
  /** Render prop function receiving portal controls */
  children: (controls: PortalControls) => React.ReactNode;
  /** Initial open state (default: false) */
  defaultOpen?: boolean;
  /** Target DOM element for portal */
  node?: HTMLElement | Element | null;
  /** Close portal when ESC key is pressed */
  closeOnEsc?: boolean;
  /** Close portal when clicking outside */
  closeOnOutsideClick?: boolean;
  /** Callback fired when portal opens (default: empty function) */
  onOpen?: () => void;
  /** Callback fired when portal closes (default: empty function) */
  onClose?: () => void;
}

interface PortalControls {
  /** Function to open the portal */
  openPortal: (event?: React.SyntheticEvent) => void;
  /** Function to close the portal */
  closePortal: () => void;
  /** Function that wraps content to be portaled */
  portal: (children: React.ReactNode) => React.ReactNode;
  /** Current open/closed state */
  isOpen: boolean;
}

Usage Examples:

// Basic modal with ESC and outside click handling
<PortalWithState closeOnOutsideClick closeOnEsc>
  {({ openPortal, closePortal, isOpen, portal }) => (
    <React.Fragment>
      <button onClick={openPortal}>Open Modal</button>
      {portal(
        <div className="modal-backdrop">
          <div className="modal">
            <h2>Modal Title</h2>
            <p>Modal content goes here</p>
            <button onClick={closePortal}>Close</button>
          </div>
        </div>
      )}
    </React.Fragment>
  )}
</PortalWithState>

// Modal with callbacks and custom target
<PortalWithState 
  closeOnEsc 
  onOpen={() => console.log('Modal opened')}
  onClose={() => console.log('Modal closed')}
  node={document.getElementById('overlay-root')}
>
  {({ openPortal, closePortal, isOpen, portal }) => (
    <div>
      <button onClick={openPortal}>
        {isOpen ? 'Close' : 'Open'} Lightbox
      </button>
      {portal(
        <div className="lightbox">
          <img src="/image.jpg" alt="Large image" />
          <button onClick={closePortal}>×</button>
        </div>
      )}
    </div>
  )}
</PortalWithState>

// Loading overlay that starts open
<PortalWithState defaultOpen>
  {({ closePortal, portal }) => 
    portal(
      <div className="loading-overlay">
        <div className="spinner">Loading...</div>
        <button onClick={closePortal}>Cancel</button>
      </div>
    )
  }
</PortalWithState>

React Version Compatibility

React Portal automatically handles React version compatibility:

  • React 16+: Uses ReactDOM.createPortal() (modern approach)
  • React 15: Falls back to ReactDOM.unstable_renderSubtreeIntoContainer() (legacy approach)
  • SSR: Detects server environment and renders null safely

Error Handling

React Portal handles cleanup automatically:

  • DOM nodes created by Portal are removed on unmount
  • Event listeners are properly cleaned up when PortalWithState unmounts
  • No memory leaks or orphaned DOM elements

Common Use Cases

  • Modals and Dialogs: Break out of parent container z-index stacking
  • Tooltips and Popovers: Position relative to viewport instead of parent
  • Loading Overlays: Cover entire page regardless of component location
  • Notifications: Render at consistent location in DOM tree
  • Lightboxes: Full-screen overlays independent of component hierarchy