What is a Portal anyway? Well, as quoted in the google dictionary, its “a doorway, gate, or other entrance.”
React v16.0 brought a similar concept of Portal that provides a way to transport a piece of UI into some other locations on to the DOM Tree while preserving its position in the React hierarchy, allowing it to maintain the properties and behaviors it has inherited from the React tree. Isn’t that amazing, you put your component in one place, and after the rendering, it’s somewhere else in the DOM tree.
How Do We Make a Portal?
Creating a portal is easy we just have to write the following code and voila we just made a Portal.
ReactDOM.createPortal(child, container)
The first argument (child
) is any renderable React child, such as an element, string, or fragment. The second argument (container
) is a DOM element. Below is a simple example of a modal that we can create through Portals.
<html>
<body>
<div id="app-root"></div>
<div id="modal-root"></div>
</body>
</html>
#app-root{
height: 10em;
width: 10em;
background: lightblue;
overflow: hidden;
}
#modal-root {
position: relative;
z-index: 999;
}
.modal {
background-color: rgba(0,0,0,0.5);
position: fixed;
height: 100%;
width: 100%;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
}
const appRoot = document.getElementById('app-root');
const modalRoot = document.getElementById('modal-root');
class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
modalRoot.appendChild(this.el);
}
componentWillUnmount() {
modalRoot.removeChild(this.el);
}
render() {
return ReactDOM.createPortal(
this.props.children,
this.el,
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {show: false};
}
openModal=()=> {
this.setState(prevState => ({
show: true
}));
}
closeModal=()=> {
this.setState(prevState => ({
show: false
}));
}
render() {
return (
<div>
<button onClick={this.openModal} >
Click Me to open
</button>
{this.state.show &&
<Modal>
<div className="modal">
<button
onClick={this.closeModal}>
Close
</button>
</div>
</Modal>
}
</div>
);
}
}
ReactDOM.render(<Parent />, appRoot);
So Now the Question Arrives When to Use the Portals?
We can use the Portals to make Modals, Tooltip. But wait can’t we make those using just plane old React component and the answer is yes we can. But what if the modal we made is to be rendered inside a parent div and the parent div is having “overflow: hidden” property. In this case, our modal component would be cropped if it crossed the dimensions of the parent div. That’s something we don’t want to happen.
Behind the Scenes
The transfer of the component happens in the Actual DOM tree, not the React Tree. React Tree will still hold the Modal where you rendered it. This means that even though a portal can be anywhere in the Actual DOM tree, it behaves just like a normal React child. Features like context and this work exactly the same regardless of whether the child is a portal. As the Modal and its children still exist in the React Virtual DOM tree. This also includes event bubbling. An event fired from inside a portal will propagate to ancestors in the containing React tree, even if those elements are not ancestors in the ActualDOM tree.