Registry / web-framework / react-portal

react-portal

JSON →
library4.3.0jsnpmunverified

react-portal simplifies the creation and management of React Portals, enabling developers to render children into a different part of the DOM tree, outside the parent component's hierarchy. This is particularly useful for modals, tooltips, lightboxes, and notifications that require specific positioning or need to break out of CSS `overflow: hidden` containers. The current stable version is 4.3.0. It leverages React's official Portal API (introduced in React 16) to provide a robust solution. A key differentiator is its dual component approach, offering both a low-level `<Portal />` for maximum control and a `<PortalWithState />` for common stateful interactions (e.g., close on ESC, close on outside click) without external dependencies. Notably, since v4.1.0, it includes a fallback mechanism to support React v15 while primarily targeting React v16 and newer, making it flexible for diverse project ecosystems. It focuses on clean markup, SSR compatibility, and minimalistic design. The project demonstrates an active maintenance cadence, with recent minor releases addressing bugs and ensuring compatibility.

npm install react-portal
INSTALL
IMPORT
SIG · REACT-PORTAL
R
react-portal
web-frameworkjavascriptv4.3.0
Install
Import
Disk
Pass rate
0/ 6
Env Coverage0 / 6
glibc
1822
musl
1822
Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
node 18226 runs
build_error
glibc
node 18226 runs
build_error
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

Portal
import { Portal } from 'react-portal';
const { Portal } = require('react-portal');
Primary component for creating basic portals without state management. While `require` works, modern React usage strongly prefers ESM imports.
PortalWithState
import { PortalWithState } from 'react-portal';
import PortalWithState from 'react-portal/lib/PortalWithState';
Higher-order component that manages its own open/closed state, including close on ESC and outside click. Direct imports from 'lib' are discouraged and brittle.
Types
import type { PortalProps, PortalWithStateProps } from 'react-portal';
TypeScript users can import specific prop types for better type checking and IntelliSense.

Demonstrates both the basic `Portal` and the stateful `PortalWithState` components, showing how to render content into `document.body` or a custom DOM node, and handle portal visibility and interactions like closing on ESC or outside clicks.

import React, { useState, useEffect } from 'react'; import { Portal, PortalWithState } from 'react-portal'; import { createRoot } from 'react-dom/client'; const App = () => { const [isBasicPortalOpen, setIsBasicPortalOpen] = useState(false); // For demonstration purposes, create a target node if it doesn't exist useEffect(() => { if (typeof document !== 'undefined' && !document.getElementById('my-custom-portal-target')) { const div = document.createElement('div'); div.id = 'my-custom-portal-target'; document.body.appendChild(div); } }, []); return ( <div> <h1>React-Portal Example</h1> <h2>Basic Portal</h2> <button onClick={() => setIsBasicPortalOpen(!isBasicPortalOpen)}> Toggle Basic Portal ({isBasicPortalOpen ? 'Open' : 'Closed'}) </button> {isBasicPortalOpen && ( <Portal> <div style={{ position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', background: 'white', border: '2px solid blue', padding: '20px', zIndex: 1000, boxShadow: '0 4px 8px rgba(0,0,0,0.1)' }}> <p>This is a basic portal injected into <code>document.body</code>.</p> <button onClick={() => setIsBasicPortalOpen(false)}>Close</button> </div> </Portal> )} <h2>PortalWithState</h2> <PortalWithState closeOnOutsideClick closeOnEsc> {({ openPortal, closePortal, isOpen, portal }) => ( <React.Fragment> <button onClick={openPortal} disabled={isOpen}> {isOpen ? 'Portal Open' : 'Open Advanced Portal'} </button> {portal( <div style={{ position: 'fixed', top: '60%', left: '50%', transform: 'translate(-50%, -50%)', background: 'lightgreen', border: '2px solid darkgreen', padding: '25px', zIndex: 1001, boxShadow: '0 6px 12px rgba(0,0,0,0.15)' }}> <p> This is a more advanced Portal. It handles its own state. <br /> <button onClick={closePortal}>Close me!</button>, hit ESC or click outside of me. </p> <p>Status: {isOpen ? 'Open' : 'Closed'}</p> </div> )} </React.Fragment> )} </PortalWithState> <h2>Custom Node Portal</h2> <p>This portal targets a custom div with id 'my-custom-portal-target'.</p> <Portal node={document && document.getElementById('my-custom-portal-target')}> <div style={{ border: '1px dashed orange', padding: '10px', marginTop: '10px' }}> Content portaled to #my-custom-portal-target. </div> </Portal> </div> ); }; // Mount the App to a root element if (typeof document !== 'undefined') { const rootElement = document.getElementById('root'); if (!rootElement) { const newRoot = document.createElement('div'); newRoot.id = 'root'; document.body.appendChild(newRoot); } const root = createRoot(document.getElementById('root')!); // Non-null assertion is safe after check root.render(<App />); }
Debug
Known issues
breakingVersion 4.0.0 was a complete rewrite, dropping support for React versions older than 16.0.0, as it fully adopted the official `ReactDOM.createPortal` API. While v4.1.0 added a fallback for React 15, initial upgrade to 4.0.0 required React 16+.
fix
Upgrade your project's React and React-DOM versions to 16.0.0 or newer. If maintaining React 15 support is critical, ensure `react-portal` is at least v4.1.0.
affects: 4.0.0
breakingSince version 3.0.0, direct styling (inline styles or `className`) on the main `react-portal` component's root div is no longer supported. The component is intended to be unstyled to avoid DOM clutter.
fix
Wrap the children of `<Portal>` or `<PortalWithState>` in your own `div` or other element, and apply styling to this wrapper element instead.
affects: >=3.0.0
breakingIn version 2.0.0, the element designated by the `openByClickOn` prop is no longer wrapped by an unnecessary `div` element, and the `openByClickOn` className was removed. This was done to provide cleaner markup, particularly for inline elements like buttons.
fix
Adjust your CSS selectors and component structure if you relied on the `openByClickOn` wrapper div or its className for styling or layout. The clicked element will now appear directly in the DOM.
affects: >=2.0.0
gotchaWhen using `PortalWithState`, ensure the single child is a function that returns actual React elements. The content to be portaled must be explicitly passed to the `portal` render prop function.
fix
Structure your `PortalWithState` like this: `<PortalWithState>{({ portal }) => <div>{portal(<p>My content</p>)}</div>}</PortalWithState>`. Do not return the render prop object directly.
affects: >=4.0.0
Errors
Common errors & fixes
TypeError: ReactDOM.createPortal is not a function
Attempting to use `react-portal` v4.0.0 with a React version older than 16.0.0.
fix
Upgrade `react` and `react-dom` to at least version 16.0.0. If you must support React 15, upgrade `react-portal` to v4.1.0 or later for its fallback mechanism.
ReferenceError: document is not defined
Accessing the `document` object or rendering `react-portal` components directly in a Server-Side Rendering (SSR) environment without client-side checks.
fix
Ensure `Portal` components are only rendered on the client-side, or use conditional rendering based on `typeof document !== 'undefined'` for any custom logic that interacts with the DOM.
Objects are not valid as a React child (found: object with keys {openPortal, closePortal, isOpen, portal}). If you meant to render a collection of children, use an array instead.
Incorrect usage of `PortalWithState` where its function child returns the render props object directly instead of calling the `portal` function with the content to be portaled.
fix
The function child of `PortalWithState` must return React elements, and the actual content to be portaled should be passed as an argument to the `portal` render prop function. For example: `{({ openPortal, portal }) => (<button onClick={openPortal}>{portal(<p>Content</p>)}</button>)}`.
Upgrade
Version history
4.3.0latest on npm
Audit
Dependencies
reactrequiredCore library for building user interfaces, required by all React components.
react-domrequiredProvides DOM-specific rendering methods, essential for mounting React components to the DOM and utilizing `createPortal`.
Agent activity
4 hits · last 30 days
node
4
Resources
react-portal — npm install react-portal · libregistry