In React, Portals provide a way to render components outside the main DOM hierarchy of a React application. This means that you can render content outside the root element of the React component tree, making it useful for scenarios like modals, tooltips, and popups, where elements need to be rendered outside their parent container but still maintain their React component lifecycle.
1. What is a React Portal?
A Portal in React is a mechanism that allows you to render a child component into a DOM node that exists outside the DOM hierarchy of the parent component. Despite being rendered outside the parent component’s DOM hierarchy, the portal component still behaves like a regular React component. It still participates in the React component tree, including updates, events, and context, but its rendered output can be appended to a different part of the DOM.
You can use the ReactDOM.createPortal()
method to create a portal, passing two arguments:
- The React element you want to render.
- The DOM node in which you want to render that element.
2. Basic Syntax of React Portals
The basic syntax to create a portal is:
ReactDOM.createPortal(child, container)
child
: The React component or element you want to render.container
: The DOM node where the child element should be appended (this can be any valid DOM node).
3. Example: Creating a Simple Portal
Let’s see a basic example where we use a portal to render a modal outside the main DOM hierarchy:
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const Modal = ({ message, onClose }) => {
return (
<div style={{ position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', background: 'white', padding: '20px', border: '1px solid black' }}>
<p>{message}</p>
<button onClick={onClose}>Close</button>
</div>
);
};
const App = () => {
const [showModal, setShowModal] = useState(false);
const openModal = () => {
setShowModal(true);
};
const closeModal = () => {
setShowModal(false);
};
return (
<div>
<h1>React Portal Example</h1>
<button onClick={openModal}>Open Modal</button>
{/* Using React Portal to render the modal outside of App component */}
{showModal && ReactDOM.createPortal(
<Modal message="This is a modal!" onClose={closeModal} />,
document.getElementById('portal-root') // The target DOM node outside the main root
)}
</div>
);
};
export default App;
In this example:
- We have a button to trigger the modal, and when clicked, it shows a modal rendered outside the main DOM hierarchy.
- The modal is rendered into a DOM element with the id
portal-root
, which is outside the root element of the React app (typicallydiv#root
).
Important: You’ll need to create the portal-root
element in the HTML file for the modal to be rendered outside the React root.
Example of index.html
(typically found in public/index.html
):
<body>
<div id="root"></div> <!-- React App Root -->
<div id="portal-root"></div> <!-- Portal Target DOM Node -->
</body>
4. Why Use Portals?
Portals are especially useful in the following scenarios:
- Modals: Modals, dialogs, and overlays often need to be rendered at the top level of the DOM, above other content, but still remain part of the React component tree for state, context, and event handling.
- Tooltips & Popups: When you need to render floating components (like tooltips, dropdowns, and popups) that might be positioned in relation to other elements on the page.
- Global Components: Components that need to be placed outside of the normal React DOM hierarchy but still interact with the React component lifecycle, such as notification bars, alert boxes, or toast messages.
- Portals and z-index: If your components (like modals or popups) need to appear above other UI elements, portals help you manage their rendering order without worrying about nested elements or z-index issues.
5. Portal with Event Handling
Even though portals render outside the DOM hierarchy, they still maintain the React component lifecycle, which includes event handling and state. For instance, you can attach event listeners, handle user interactions, and manage state in the portal component just like any other React component.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
const Tooltip = ({ message, onClose }) => {
return (
<div style={{ position: 'absolute', top: '50px', left: '50px', padding: '10px', backgroundColor: 'black', color: 'white' }}>
<p>{message}</p>
<button onClick={onClose}>Close</button>
</div>
);
};
const App = () => {
const [showTooltip, setShowTooltip] = useState(false);
const handleShowTooltip = () => {
setShowTooltip(true);
};
const handleHideTooltip = () => {
setShowTooltip(false);
};
return (
<div>
<h1>React Portal Example</h1>
<button onMouseEnter={handleShowTooltip} onMouseLeave={handleHideTooltip}>
Hover me for Tooltip
</button>
{/* Render the Tooltip via portal */}
{showTooltip && ReactDOM.createPortal(
<Tooltip message="This is a tooltip!" onClose={handleHideTooltip} />,
document.getElementById('tooltip-root')
)}
</div>
);
};
export default App;
6. Portal with Multiple Elements
You can also use portals to render multiple elements at once, depending on the needs of your UI. For example, if you want to render both a modal and a notification at the same time, you can render them using separate portals or even to the same portal target if needed.
7. Key Benefits of Using Portals
- Flexibility: Portals allow for greater flexibility in rendering components outside of their parent hierarchy while still keeping the power of React’s component lifecycle.
- Event Handling: Portals preserve the ability to manage state, context, and events. They remain fully integrated with the React system, even though they may be rendered outside the root DOM node.
- Improved UI: Useful for handling UI elements that should not be nested within their parent DOM structure but still need to interact with other parts of the React app (e.g., modals, tooltips, popups).
- Access to Layout Management: You can easily manage z-index and stacking contexts for elements that need to visually appear outside the parent hierarchy but still function as part of the React component tree.
8. Potential Limitations
- Accessibility Concerns: Portals can introduce some complexity when dealing with accessibility, especially for focus management. You may need to manually handle focus when opening/closing modals or other popups.
- Performance: Excessive use of portals, particularly with large and complex DOM structures, could potentially introduce performance issues, especially if the portal target is far outside the normal DOM flow.