What is React portal? From the definition in the React docs, portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. Before we try to understand why we need React portal, let us review how React renders a component.
React is declarative
By design, React is responsible for most of the API calls to the native UI (for example DOM API for the web). We can just focus on defining what the UI should look like. React handles things like writing to the DOM and rendering output to the screen.
React Components facilitate its declarative nature
React components are the basic unit that allows you to define what you want to be rendered on the screen.
Because components are self-contained parts of a whole, they allow the creation of reusable pieces of UI.
Components accept inputs such as props and/or state and render output.
The output rendered by components is React elements. Component-rendered outputs are mostly written in JSX syntax. JSX is converted to React elements during compilation.
As we mentioned earlier, React elements are the render outputs of components. Even though they are mostly written in JSX, these outputs are converted to React.createElement() calls.
React.createElement() is responsible for creating React elements as plain objects that describe the intended structure of the UI.
React element objects have a type property. This property describes the type of element.
The code snippet describes the simplest unit of a React element which is the DOM element. The type properties of DOM elements are strings. These strings are the name of HTML tags (for example, "button").
From the snippet, we can see that the type property of a component element is not a string. In this case, it is a function. If we defined our component as a class, the type property would indicate that.
Something else to note from the code is that this component is nested. From the JSX, we can see that it wraps a child component. This is represented in the element object props property.
Because IconButton has nested components, it has a component tree. The IconButton is the parent component, and any wrapped component is the child. In this case, the CartIcon.
The CartIcon will be always rendered and mounted to the IconButton DOM node. Whenever you need the CartIcon to be rendered in another parent DOM node, the component needs to be declared again in the new parent component.
From the attached screenshot, we can see how the CartIcon is rendered within the IconButton.
For most use cases on the browser, the way react renders nested components work just fine. What if we need to render a component outside of the component where it is declared or invoked?
Using our current example of the CartIconButton, what if we need to render a modal when the button is clicked? And why is this an issue for the standard way react renders components?
A modal window is an element that sits on top of an application’s main window.
In our use case, the modal needs to occupy the full width and height of the browser window.
But to open and close the modal using the state controlled by the CartButtonIcon, the modal needs to be invoked within the same component as the CartButtonIcon.
From the snippet, we have nested both the IconButton and the Modal components within the same parent component. However, while we need the IconButton to mount as a child node of this parent DOM node, the Modal component needs to be mounted on a DOM node that occupies the full width and length of the browser window. And clearly, the CartIconButton does not meet this criterion.
React portal to the rescue
Because React mounts a child DOM node within a tree to the parent component, you can’t render a child element outside of where it is declared. Unless you declare that child component as a portal rather than as a React element.
From the snippet, the Modal component returns a portal instead of the usual JSX.
A React portal is created using the method ReactDOM.createPortal. Remember that JSX compiles to React.createElement.
The createPortal method is only available in ReactDOM. ReactDOM is responsible for APIs designed specifically for the browser.
Defining a child element as a portal will tell React that this child component intends to be mounted outside of the parent DOM node it is invoked in. In our case, the ref to the DOM node is passed through context. And the context provider is defined at the top of the application component tree; this will ensure that the target DOM node covers the full browser window.