React 16 was out sometime back with cool new features like fragments, portals, custom DOM attributes and more. Portals no longer have to be called with this unstable_renderSubtreeIntoContainer , instead its just createPortal now.

This blog will cover on how one can harness the power of portals in older versions of React which had portal as an unstable feature, as I did not find many examples on how to do so.

Till now React only allowed us mount children inside a parent and not anywhere else which made us design the app in a different way, but not anymore as portals allows to render a child outside of its parent and still keep it bound to its parent state. Cool right!

Lets begin with this simple example of Image Gallery which needs a modal to be rendered just inside body tag. You can stop at any point and look at the code here and you can check the demo here. I have used react-webpack-boilerplate to quickly start off with the app.

Clone the repository and just do npm install to install the dependencies. I am using React 15.6.2.

Component structure of our app:

-- App

-- Header

-- Gallery

-- Image

In this app whenever a user clicks on an image we would like to show a modal with that image, which is where portal comes in handy. In react 15 to implement a portal we need to call unstable_renderSubtreeIntoContainer method of ReactDOM . Do not worry its not at all unstable infact Facebook devs were using it too prior to the release of React 16.

Lets write our App component:

The app looks something like this now:

Image Gallery

Here we pass the image list to Gallery and render the images. Next we define Gallery component where all the magic happens:

So here we define a modalClickHandler which will be passed to Image component. Now whenever a user clicks on the image, src and title will be updated.

Before adding a portal, lets just see how the portal works. We need to pass three parameters into the method unstable_renderSubtreeIntoContainer .

context i.e. this component which should be ported node to which it should be appended

Let’s first define the node to which it should be appended:

// create a div

this.imagePreviewContainer = document.createElement('div'); // add a class if you want to add some styles to the container

this.imagePreviewContainer.className = 'image-preview-container hide';

Now, whenever Gallery is rendered, we want imagePreviewContainer to be appended to body . Lets do that when the component mounts:

componentDidMount() {

this.mainContainer = document.getElementsByTagName('body')[0];

this.mainContainer.appendChild(this.imagePreviewContainer);

}

Lets define our Modal component which will take src , title and show a cool modal with an overlay.

We will add a hook to modalClickHandler , so that whenever state is updated with image src and title we open the modal. Let’s update our modalClickHandler code:

modalClickHandler(src, title) {

this.setState({

src,

title,

}, this.renderContent);

}

Now, renderContent will be called on setState , this will be responsible for appending Modal to imagePreviewContainer . Let’s add the final piece of code which will port Modal outside of its parent ( Gallery ).

renderContent() { // removes `hide` class from previewContainer

this.imagePreviewContainer.classList.toggle('hide'); // This ports Modal outside of parent

ReactDOM.unstable_renderSubtreeIntoContainer(

this,

<Modal

src={this.state.src}

title={this.state.title}

modalClose={this.modalClose}

/>,

this.imagePreviewContainer

);

}

And that’s it. Now if we click on any image it a modal opens up with the image in full screen mode. Lets see how the DOM tree looks when the modal is open:

Modal with Image

Console

We can see here that Modal is ported outside of the AppContainer .

Let me know in comments below if you have used portals and what was it used for.