React Portals are lit 🔥 
Tags: react, javascript, webdev, ux
Published: 2019-07-28 15:37:59



Recently I was introduced to Reacts' createPortal API, which was nothing short of amazing.

Let me share my experiences with it!

Being a professional **Ember developer**, my love towards React has never faded away. React with its' component oriented architecture boosts productivity, ensures stable code and is backed up with strong community.

I don't wanna bore you, with this sort of things that you(probably many Web devs) hear in **routine**.

I think, Its' time to get our hands dirty with **Portals** :fire:

**'Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component'**

Generally, not everyone in the world can understand the definition in the official docs in a single glance!, atleast **NOT ME!** (jus kidding, Reacts' docs on Portals is more beginner friendly peeps, [go check it out](https://reactjs.org/docs/portals.html))

So i decided to have a practical approach with it:

As stated in the definition, Portals provide a way to render children of a react component **somewhere else in the DOM, not in the same hierarchy!**

As soon i realised it, i was ended up with nothing but questions.

OMG what about the event bubbling? and many...

Being a profressional ember developer, i have used [Ember Wormhole](https://github.com/yapplabs/ember-wormhole), it is an addon probably does the similar work of Portals in Ember.

I kept digging more about Portals. One thing i explored is its' use-case in [Modal Dialogs](https://www.w3.org/TR/wai-aria-practices-1.1/#dialog_modal).

I built a modal component with bootstrap(overriding some of bootstrap styles) in react similar to this :point_down:

```js
//Modal.js
import React from "react";
import ReactDOM from "react-dom";
export default class Modal extends React.Component {
  onClose = e => {
    this.props.onClose && this.props.onClose(e);
  };
  render() {
    let modal = (<div
      class="modal fade"
      id="exampleModalCenter"
    >
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLongTitle">
              Modal title
            </h5>
            <button
              type="button"
              class="close"
            >
              <span aria-hidden="true">&times;</span>
            </button>
          </div>
          <div class="modal-body">...</div>
          <div class="modal-footer">
            <button
              type="button"
              class="btn btn-secondary"
            >
              Close
            </button>
            <button type="button" class="btn btn-primary">
              Save changes
            </button>
          </div>
        </div>
      </div>
    </div>
    );
    return (modal);
  }
}
```

I rendered it as a child to App :point_down:

```js
//App.js    
import React from "react";
import Modal from "./Modal-Compo";

export default class App extends React.Component {
  onClose = e => {
    this.props.onClose && this.props.onClose(e);
  };

  render() {
    let alignCenter = {
      display: "flex",
      alignItems: "center",
      justifyCenter: "center",
      height: "200px",
      overflow: "hidden",
      width: "50%",
      margin: "auto",
      marginTop: "10%"
    };
    return (
    <div style={alignCenter}>
      <p style={{ height: "100%", margin: "0" }}>
        //some random 100 lines
      </p>
      <Modal onClose={this.onClose}/>
    </div>
  )
 }
}


```

Atlast rendered the App component in the root element :point_down:

```js
//Index.js
import React from "react";
import ReactDOM from "react-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import "jquery/dist/jquery.min.js";
import "bootstrap/dist/js/bootstrap.min.js";
import App from "./components/App";
import "./styles.css";

function WhatAreModals() {
  return (
    <div style={{ height: "100vh" }} className="App">
      <App />
      <button
        type="button"
        className="btn btn-primary"
        data-toggle="modal"
        data-target="#exampleModalCenter"
      >
        Launch demo modal
      </button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<WhatAreModals />, rootElement);

```

Finally my prototype was ready :smile:

When i clicked the Launch demo modal CTA, this happened (oopsy) :confused:

<img src="https://i.imgur.com/3PFoAgv.gif"/>


The culprit is the App component styled **'overflow:hidden'**, as in our case the Modal component is rendered as a child of App whose overflow is hidden, our Modal never shows up :weary:

Here is where the life saver Portal comes in :fire:

I just made a tweak in my Modal component and the index.html(created another root element for Modal to be rendered)

```js
//index.html
<div id="root"></div>
<div id="modal-root"></div>
```

Rendered Modal in Portal, changed return statement by implementing **createPortal**

```js
//Modal.js
ReactDOM.createPortal(modal, document.getElementById("modal-root"));
```

It worked seamlessly,

<img src="https://i.imgur.com/UIzQ4zs.gif"/>

The problem was solved by breaking the Modal component out of the container, out of the hierarchy.

But suddenly i got into a confusion, as the hierarchy is broken i doubted whether event bubbling will occur? (I think, Many will question this!).

I went on **digging deeper** :grin:

Native DOM Snapshot:


<img src="https://i.imgur.com/8H0KGDq.png"/>

React DOM: 

<img src="https://i.imgur.com/UPk7x6D.png"/>

Finally, i was satisfied seeing this, probably many would be :relieved:
From the snapshots, we come to know that the hierarchy is unaltered in Reacts' Virtual DOM, so event bubbling will happen with ease.

Portals can be widely used when a parent component has an **overflow: hidden** or **z-index style**, but you need the child to visually “break out” of its container. For example, dialogs, hovercards, and tooltips.

I feel this post would've satisfied you on Reacts' createPortal API, if yes, feel free to share this with your colleague web devs as well.