Step-by-Step Guide to Implementing React createPortal for Better UI
Using React createPortal for effective content rendering.
createPortal
lets you render some children into a different part of the DOM.
<div>
<SomeComponent />
{createPortal(children, domNode, key?)}
</div>
createPortal(children, domNode, key?)
To create a portal, call createPortal
, passing some JSX, and the DOM node where it should be rendered:
import { createPortal } from 'react-dom';
<div>
<p>This child is placed in the parent div.</p>
{createPortal(
<p>This child is placed in the document body.</p>,
document.body
)}
</div>
Parameters
children
: Anything that can be rendered with React, such as a piece of JSX (e.g.<div />
or<SomeComponent />
), a Fragment (<>...</>
), a string or a number, or an array of these.domNode
: Some DOM node, such as those returned bydocument.getElementById()
. The node must already exist. Passing a different DOM node during an update will cause the portal content to be recreated.optional
key
: A unique string or number to be used as the portal’s key.
Returns
createPortal
returns a React node that can be included into JSX or returned from a React component. If React encounters it in the render output, it will place the provided children
inside the provided domNode
.
Caveats
- Events from portals propagate according to the React tree rather than the DOM tree. For example, if you click inside a portal, and the portal is wrapped in
<div onClick>
, thatonClick
handler will fire. If this causes issues, either stop the event propagation from inside the portal, or move the portal itself up in the React tree.
Usage
Rendering to a different part of the DOM
Portals let your components render some of their children into a different place in the DOM. This lets a part of your component “escape” from whatever containers it may be in. For example, a component can display a modal dialog or a tooltip that appears above and outside of the rest of the page.
To create a portal, render the result of createPortal
with some JSX and the DOM node where it should go:
import { createPortal } from 'react-dom';
function MyComponent() {
return (
<div style={{ border: '2px solid black' }}>
<p>This child is placed in the parent div.</p>
{createPortal(
<p>This child is placed in the document body.</p>,
document.body)}
</div>
);}
Rendering a modal dialog with a portal
You can use a portal to create a modal dialog that floats above the rest of the page, even if the component that summons the dialog is inside a container with overflow: hidden
or other styles that interfere with the dialog.
In this example, the two containers have styles that disrupt the modal dialog, but the one rendered into a portal is unaffected because, in the DOM, the modal is not contained within the parent JSX elements.
//App.js
import NoPortalExample from './NoPortalExample';
import PortalExample from './PortalExample';
export default function App() {
return (
<>
<div className="clipping-container">
<NoPortalExample />
</div>
<div className="clipping-container">
<PortalExample />
</div>
</>
);
}
//NoPortalExample.jsx
import ModalContent from './ModalContent.js';
export default function NoPortalExample() {
const [showModal, setShowModal] = useState(false);
return (
<>
<button onClick={() => setShowModal(true)}>
Show modal without a portal
</button>
{showModal && (
<ModalContent onClose={() => setShowModal(false)} />
)}
</>
);
}
//PortalExample.jsx
import { useState } from 'react';
import { createPortal } from 'react-dom';
import ModalContent from './ModalContent.js';
export default function PortalExample() {
const [showModal, setShowModal] = useState(false);
return (
<>
<button onClick={() => setShowModal(true)}>
Show modal using a portal
</button>
{showModal && createPortal(
<ModalContent onClose={() => setShowModal(false)} />,
document.body
)}
</>
);
}
//ModelContent.jsx
export default function ModalContent({ onClose }) {
return (
<div className="modal">
<div>I'm a modal dialog</div>
<button onClick={onClose}>Close</button>
</div>
);
}