Render Elements Outside the Current React Tree using Portals in React 16

Nik Graf
InstructorNik Graf

Share this video with your friends

Send Tweet
Published 6 years ago
Updated 5 years ago

By default the React Component Tree directly maps to the DOM Tree. In some cases when you have UI elements like overlays or loading bars this can be limiting. React 16 therefor ships with the new portal feature allowing you to attach parts of the Component tree inside a different root element.

This lesson explores the new functionality by building an <Overlay/> component that renders out its children and creates a closeable overlay outside its DOM node.

We can leverage the new ReactDOM function createPortal. It accepts two arguments. The first one is the new subtree containing components. In our case, we simply provide a div containing the text welcome. The second argument is the target container.

Here we're going to query for the element with the ID portalContainer, which I already added inside the index.html right after our React root. As you can see, our welcome box is now rendered, although the code for the welcome text is inside the app component, which is located inside the container root.

If you look at the DOM structure, it's actually rendered inside the portalContainer. This comes in very handy for things like overlays. Let me demonstrate this by adding the class named overlay that I prepared previously to a div. It appears like an overlay. So far, so good.

The current approach requires us to extend index.html. We can give the component itself the control to add and remove new DOM elements right at the end of the body. To do this, we're going to extract our functionality to an overlay component.

In the constructor, we call super, and right after that, create an overlay container using createElement. Right after its creation, we append this div to the document body. In the render function, we don't need a wrapping element. We can return the portal right away.

Its rendered content is the overlay, and then the children passed to the overlay component. The target is the overlay container that we created in the constructor. By inspecting the DOM, we can verify that the div was created, and the overlay attached to it. Pretty cool.

When using this technique, I recommend you to also properly clean up, meaning to remove the div that we created in the constructor. Otherwise, you might create a lot unused divs that bloat your DOM tree unnecessarily.

We add the React life cycle method, componentWillUnmount, and in there, remove the overlay container using document.body.removeChild. In addition, we adding a closing X inside the overlay. The idea is to remove the overlay component when the X is clicked.

To make that happen, in the app component, we add the state, overlayActive, and set it to true. Then we add a close overlay function, setting overlayActive to false.

At last, we add the condition that the overlay is only rendered when the overlay active is set to true, as well as the handler on close. Switching back to the browser, you can see once we click X, the overlay is gone.

Let's refresh and do it one more time, but take a closer look at the DOM. As you can see, then check the container div is removed.