0
# React Portal
1
2
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.
3
4
## Package Information
5
6
- **Package Name**: react-portal
7
- **Package Type**: npm
8
- **Language**: JavaScript (React)
9
- **Installation**: `npm install react-portal` or `yarn add react-portal`
10
11
## Core Imports
12
13
```javascript
14
import { Portal, PortalWithState } from 'react-portal';
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { Portal, PortalWithState } = require('react-portal');
21
```
22
23
## Basic Usage
24
25
```jsx
26
import React from 'react';
27
import { Portal, PortalWithState } from 'react-portal';
28
29
// Basic Portal usage
30
const MyModal = ({ isOpen, children }) => (
31
isOpen && <Portal>{children}</Portal>
32
);
33
34
// PortalWithState usage with built-in controls
35
const AdvancedModal = () => (
36
<PortalWithState closeOnOutsideClick closeOnEsc>
37
{({ openPortal, closePortal, isOpen, portal }) => (
38
<React.Fragment>
39
<button onClick={openPortal}>Open Modal</button>
40
{portal(
41
<div style={{ background: 'white', padding: '20px' }}>
42
<h2>Modal Content</h2>
43
<button onClick={closePortal}>Close</button>
44
</div>
45
)}
46
</React.Fragment>
47
)}
48
</PortalWithState>
49
);
50
```
51
52
## Architecture
53
54
React Portal is built around React's Portal API with the following key components:
55
56
- **Portal Component**: Core portal functionality with automatic React version compatibility (16+ vs 15)
57
- **PortalWithState Component**: Stateful wrapper providing built-in open/close management
58
- **Compatibility Layer**: Automatic fallback between modern `ReactDOM.createPortal` and legacy `unstable_renderSubtreeIntoContainer`
59
- **Event Management**: Built-in ESC key and outside click handling for modals and popups
60
- **SSR Support**: Server-side rendering compatibility through DOM environment detection
61
62
## Capabilities
63
64
### Basic Portal Creation
65
66
Core portal component that transports React elements into a React Portal, breaking out of normal DOM hierarchy for proper styling and positioning.
67
68
```javascript { .api }
69
/**
70
* Portal component that renders children into a React Portal
71
*/
72
class Portal extends React.Component<PortalProps> {}
73
74
interface PortalProps {
75
/** React elements to be portaled */
76
children: React.ReactNode;
77
/** Optional target DOM element (defaults to auto-created div in document.body) */
78
node?: HTMLElement | Element | null;
79
}
80
```
81
82
**Usage Examples:**
83
84
```jsx
85
// Portal to document.body (default)
86
<Portal>
87
<div>This content appears at the end of document.body</div>
88
</Portal>
89
90
// Portal to custom element
91
const customTarget = document.getElementById('modal-root');
92
<Portal node={customTarget}>
93
<div>This content appears in the custom element</div>
94
</Portal>
95
96
// Conditional portal
97
{isModalOpen && (
98
<Portal>
99
<div className="modal-overlay">
100
<div className="modal-content">Modal content here</div>
101
</div>
102
</Portal>
103
)}
104
```
105
106
### Stateful Portal Management
107
108
Advanced portal component with built-in state management, event handling, and render prop pattern for complete portal control.
109
110
```javascript { .api }
111
/**
112
* Stateful portal component using render prop pattern
113
*/
114
class PortalWithState extends React.Component<PortalWithStateProps> {}
115
116
interface PortalWithStateProps {
117
/** Render prop function receiving portal controls */
118
children: (controls: PortalControls) => React.ReactNode;
119
/** Initial open state (default: false) */
120
defaultOpen?: boolean;
121
/** Target DOM element for portal */
122
node?: HTMLElement | Element | null;
123
/** Close portal when ESC key is pressed */
124
closeOnEsc?: boolean;
125
/** Close portal when clicking outside */
126
closeOnOutsideClick?: boolean;
127
/** Callback fired when portal opens (default: empty function) */
128
onOpen?: () => void;
129
/** Callback fired when portal closes (default: empty function) */
130
onClose?: () => void;
131
}
132
133
interface PortalControls {
134
/** Function to open the portal */
135
openPortal: (event?: React.SyntheticEvent) => void;
136
/** Function to close the portal */
137
closePortal: () => void;
138
/** Function that wraps content to be portaled */
139
portal: (children: React.ReactNode) => React.ReactNode;
140
/** Current open/closed state */
141
isOpen: boolean;
142
}
143
```
144
145
**Usage Examples:**
146
147
```jsx
148
// Basic modal with ESC and outside click handling
149
<PortalWithState closeOnOutsideClick closeOnEsc>
150
{({ openPortal, closePortal, isOpen, portal }) => (
151
<React.Fragment>
152
<button onClick={openPortal}>Open Modal</button>
153
{portal(
154
<div className="modal-backdrop">
155
<div className="modal">
156
<h2>Modal Title</h2>
157
<p>Modal content goes here</p>
158
<button onClick={closePortal}>Close</button>
159
</div>
160
</div>
161
)}
162
</React.Fragment>
163
)}
164
</PortalWithState>
165
166
// Modal with callbacks and custom target
167
<PortalWithState
168
closeOnEsc
169
onOpen={() => console.log('Modal opened')}
170
onClose={() => console.log('Modal closed')}
171
node={document.getElementById('overlay-root')}
172
>
173
{({ openPortal, closePortal, isOpen, portal }) => (
174
<div>
175
<button onClick={openPortal}>
176
{isOpen ? 'Close' : 'Open'} Lightbox
177
</button>
178
{portal(
179
<div className="lightbox">
180
<img src="/image.jpg" alt="Large image" />
181
<button onClick={closePortal}>×</button>
182
</div>
183
)}
184
</div>
185
)}
186
</PortalWithState>
187
188
// Loading overlay that starts open
189
<PortalWithState defaultOpen>
190
{({ closePortal, portal }) =>
191
portal(
192
<div className="loading-overlay">
193
<div className="spinner">Loading...</div>
194
<button onClick={closePortal}>Cancel</button>
195
</div>
196
)
197
}
198
</PortalWithState>
199
```
200
201
## React Version Compatibility
202
203
React Portal automatically handles React version compatibility:
204
205
- **React 16+**: Uses `ReactDOM.createPortal()` (modern approach)
206
- **React 15**: Falls back to `ReactDOM.unstable_renderSubtreeIntoContainer()` (legacy approach)
207
- **SSR**: Detects server environment and renders `null` safely
208
209
## Error Handling
210
211
React Portal handles cleanup automatically:
212
213
- DOM nodes created by Portal are removed on unmount
214
- Event listeners are properly cleaned up when PortalWithState unmounts
215
- No memory leaks or orphaned DOM elements
216
217
## Common Use Cases
218
219
- **Modals and Dialogs**: Break out of parent container z-index stacking
220
- **Tooltips and Popovers**: Position relative to viewport instead of parent
221
- **Loading Overlays**: Cover entire page regardless of component location
222
- **Notifications**: Render at consistent location in DOM tree
223
- **Lightboxes**: Full-screen overlays independent of component hierarchy