How to Improve DOM Structure with React Portal
Tags: javascript, webdev, react, tutorial
Published: 2022-05-30 13:15:36


## What is it?
According to the [official React documentation](https://reactjs.org/docs/portals.html),
> Portals provide a first-class way to render children into a DOM node that exists outside a DOM hierarchy of the parent component.

Take a look at this example - let's say you have a `Calculator` component, inside which there is a `Buttons` component. It would look something like this:

![An example of nested components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxyzo4kefqo9nybtv8ra.png)

The root component `App` along with all its child components will be rendered inside a single DOM node (most likely a div with an id of `#root`). With React Portal, a child component like `Buttons` can be rendered outside the div with an id of `#root`. You can imagine the structure of the DOM to look something like this:


![DOM structure of nested components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n2xsr9phdsz4evzwzq40.png)

## Why should I know this?
In certain situations, it is necessary to render some JSX or a component outside the root element. The best example of such a situation would be a modal.

A modal would typically cover the entire screen. One would expect this to be reflected in the DOM structure as well. However, that's not what happens in React. If a modal is nested inside a component, that is also how the DOM structure would look like. This can be confusing for people who use screen readers. From an accessibility standpoint, this is an issue.

Resolving this might be a bit easy to do in Vanilla JS and HTML, but harder to do in React. Since React applications have a single mount point, putting an element or component outside this mount point is a challenge. With React Portal, this becomes an easy task.

Although the element or component will be *portaled* to a different DOM node, it will still function as a regular React element. For our modal this means that it is in a different DOM node than the mount point. But it can still receive props and state and behave like a regular nested React element.

## How do I use it?
Let's use the modal example from the section above. Creating a React Portal and mounting it to a different DOM node can be done in 2 steps:

### Step 1:
Create another DOM node for mounting the modal:

![Creating a separate DOM node](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7dt54wepkzejdl9021xu.png)

The React application will be mounted to the div with an id of `#root`. And the modal will be mounted to the div with an id of `#modal-root`.

### Step 2:
Create a Portal wrapper component:

![Creating a wrapper component with React Portals](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/353nz3778teghcb357ld.png)

This wrapper component will take a child element and create a Portal for it. The `useEffect` hook mounts the element and cleans up when the component is unomunted.

Here is how it might look:

![Wrapping the Modal in the wrapper component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1jfkduvspr5687h81md4.png)

Even though the `Modal` component is nested in the app hierarchy, it will look different in the DOM structure:

![New DOM structure after using React Portals](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qneiqnrxh6wze23usdko.png)

In the real DOM structure, you won't see the `Modal` component directly like this, but a div instead. This is simply a demonstration.

## Extra resources
1. [This article](https://blog.logrocket.com/learn-react-portals-by-example/) has another good use-case for using React Portals.
2. A [dialog component](https://malcoded.com/posts/react-portals/) is also a good scenario where React Portals is quite handy.
3. Do you need a ref from a React Portal? Then [this solution](https://stackoverflow.com/a/46644072/12903901) for React 16 might help.
4. Learn [how to create](https://dev.to/alexandprivate/your-next-react-modal-with-your-own-usemodal-hook-context-api-3jg7) a Modal component with React Hooks, Context, and Portals.