Portals
Portals allow us to render components in DOM nodes which are outside of the parent-node of the current component hierarchy but still have access to the current component environment. A common example (but of course not the only one) is an overlay which is rendered in its own <div>
outside of the actual application.
The portal remains in the context of the component that has created it and thus has access to all data that is also available to the parent component such as its props and state. However, they are placed in entirely different locations in the rendered HTML compared to the rest of the application. Being able to access props and state is crucial for Portals, as they allow us to access common context such as translations.
Creating portals
Creating a portal is relatively simple compared to other concepts we have learned about so far. The component intended to use the portal has to call the createPortal()
method from ReactDOM and pass in a valid component as the first and an existing destination node as the second parameter.
The following example shows a common HTML snippet using portals:
While this snippet shows the corresponding React App:
As our <App />
is placed into the div
with the id of root
, the <body>
of the app would now result in this HTML snippet:
Each additional component or each additional HTML element which is used in the JSX of our App component would end up in the div
with the id="root"
. If we are dealing with a Portal however, the code would resemble the following:
Here, we can see the createPortal()
method in action: first, we indicate which type of JSX should be rendered and second, we pass in the type of container where the JSX should be rendered into. Let's place this PortalExample
component into our App:
The resulting <body>
in the HTML document will look like this:
The Portal is rendered into the #portal
node instead of the #root
node where all other content including the component itself is placed. A Portal is rendered once the component mounts and is removed from the DOM if the component containing the portal is removed from the component tree.
Portals and their relationship to their parent component
In order to further our understanding of portals, we are going to build — surprise surprise — a modal portal. The basis is formed by the same HTML which we have used in the introduction of portals before. There are two divs in the example: one in which our application is rendered and another in which we render the portal.
This time however, the modal will only open once a user has clicked a button. The portal will contain a button which allows the user to close the window. A state variable called modalIsOpen
is used to alternate between the two states and is either true or false. The ModalPortal
component will be rendered via an &&
conditional in JSX, thus it is only shown if this.state.modalIsOpen is true.
During the time in which the value of the state changes from false
to true
, the ModalPortal
component is mounted and the ModalPopup is rendered into the <div id="portal">
with a slightly transparent background. Once the value changes from true
to false
again, the ModalPortal
is removed from the App component in the component tree. React takes care to ensure that the ModalPortal
component and its contents are not found on the page anymore.
In code form, we are left with the following example:
We need to pay special attention to the this.closeModal()
method. Even though this method is defined in the App
component, it is called within the ModalPortal
component in the context of the App
component once a user has clicked on the button "Close Modal".
This method can also alter the state of component via modalIsOpen
even though the component is not placed within <div id="root">
as the rest of the components. Portals allow us to do this as the content is placed within the same component tree within React. The resulting HTML however, is different and the code is placed in a different <div>
to the rest of the application.
Last updated