DEV Community

Cover image for Demystifying React Portals-Don't let the parent enforce styles on the child
Sanskar Gupta
Sanskar Gupta

Posted on

Demystifying React Portals-Don't let the parent enforce styles on the child

A portal is defined as a doorway, gate, or other entrance, especially an imposing and a secretive one.

This same concept is applied to a react component who is able to travel through a portal and is able to render itself on a DOM node which does NOT belong to its parent's DOM hierarchy.

Why to use it?

Every UI developer might have faced a scenario where parent css styles gets applied to the children components and this takes up huge amounts of time to come up with a workaround.
React portals enables the children not to get rendered in same DOM tree as its parent ,hence they are saved from getting css being applied to them forcefully.

Some of the use cases of portals include modals, tooltips, notification bars, toasters etc.

Example use case

Consider the following piece of code

import React from "react";
import "./styles.css";
import ReactDOM from 'react-dom'

const modalRoot = document.getElementById('root')
const modalRoot = document.getElementById('another_root')

class App extends React.Component {
  state = {
    show: false
  };
  showModal = e => {
    this.setState({
      show: !this.state.show
    });
  };
  render() {
    return (
      <div style={{textAlign: 'center', maxWidth: '50%'}}>
        <button
          onClick={e => {
            this.showModal(e);
          }}
        >
          {" "}
          show Modal{" "}
        </button>

        <Modal onClose={this.showModal} show={this.state.show}>
          Text
        </Modal>
      </div>
    );
  }
}

class Modal extends React.Component {
    onClose = e => {
        this.props.onClose && this.props.onClose(e);
    };
    render() {
        if (!this.props.show) {
            return null;
        }
        return (
            <div >
                <h2>Modal Window</h2>
                <div >{this.props.children}</div>
                <div >
                    <button  onClick={this.onClose}>
                        close
                    </button>
                </div>
            </div>
        );
    }
}


ReactDOM.render(<App />, rootElement);

Here it can be seen that the parent(App) has a div whose max width is set to 50 percent , as a result this width restriction gets applied to modal as well.

Here is the result:(Click on image to get the width idea)
Alt Text

Now consider this piece of code with portals:

import React from "react";
import "./styles.css";
import ReactDOM from 'react-dom'

const modalRoot = document.getElementById('root')
const modalRoot = document.getElementById('another_root')

class App extends React.Component {
  state = {
    show: false
  };
  showModal = e => {
    this.setState({
      show: !this.state.show
    });
  };
  render() {
    return (
      <div style={{textAlign: 'center', maxWidth: '50%'}}>
        <button
          onClick={e => {
            this.showModal(e);
          }}
        >
          {" "}
          show Modal{" "}
        </button>

        <Modal onClose={this.showModal} show={this.state.show}>
          Text
        </Modal>
      </div>
    );
  }
}

class Modal extends React.Component {
    onClose = e => {
        this.props.onClose && this.props.onClose(e);
    };
    render() {
        if (!this.props.show) {
            return null;
        }
        return ReactDOM.createPortal (
            <div >
                <h2>Modal Window</h2>
                <div >{this.props.children}</div>
                <div >
                    <button  onClick={this.onClose}>
                        close
                    </button>
                </div>
            </div>, modalRoot
        );
    }
}


ReactDOM.render(<App />, rootElement);

Here is the result:
Alt Text

It can be seen that the modal is encompassing the whole width and not just the 50 percent as defined in parent.
ReactDOM.createPortal accepts two params , the jsx and the DOM node that is present outside like the div with id and "another_root"

On exploring the console:
Alt Text

It is proved that the modal is rendered under the "another_root" div and not the "root" on which the parent (App) is rendered.

The above example demonstrates the usage of a react portal considering modal as an example.

PS: It should be noted , though the child(modal) belongs to different DOM tree, there are no changes in flow of props and data i.e consider it as a normal child while dealing with props.

The above code can be found at: Link

Top comments (0)