Page Content

Tutorials

What Is Portals in React.js With Code Example

Portals in React.js

One of React.js finest features is Portals, which render children as DOM nodes outside the parent component’s hierarchy. Specific UI patterns demand this functionality to let an element explicitly deviate from its parent’s placement or styling while maintaining its React component tree logical relationship.

A specific technique for rendering children into a DOM node that is not part of the parent component’s DOM hierarchy is provided by React Portals. To accomplish this, ReactDOM.createPortal(child, domNode) is used. When developing UI elements like tooltips, popovers, and modal dialogues, this capability is quite helpful. A Portal keeps its place in the React component tree even when it renders its children to a different DOM location.

This guarantees that events coming from within the Portal will propagate up through the React component tree instead of the distinct DOM hierarchy, and that the displayed component can still access context from its parent. This makes it possible to develop adaptable wrappers that can insert unique JSX into a component in a variety of places. Common use cases include controlling keyboard attention inside modals and rendering and interacting with modal dialogues.

Portals in React.js
Portals in React.js

What is a Portal?

The output of React components is usually children in their parent’s DOM. Place child component output behind the <body> tag in HTML DOM tree to avoid stylistic or z-index conflicts with parent components, such as in modal dialogues, tooltips, or popovers. This may be accomplished using a portal without violating React’s event system or declarative nature.

Portals are created with ReactDOM.createPortal(). Mounting these children and rendering React children (any renderable React node, such as an element, string, or fragment) requires a DOM element outside the parent’s hierarchy. The children of the Portal operate like regular React children, which means they may access context and take part in React’s event bubbling mechanism, despite being rendered into a distinct DOM node.

Why Use Portals?

Portals are especially helpful for user interface elements that need to overflow CSS attributes, escape their parent’s clipping, or overlap other areas of the program. Typical usage cases include of:

Modals and Dialogs: Regardless of where its parent component is in the DOM, a modal must show up above all other content. Portals make it possible to attach the modal’s HTML straight to the <body> tag, preventing it from being impacted by ancestor CSS attributes like as z-index or overflow: hidden.

Tooltips and Popovers: Like modals, tooltips and popovers must float above other content and may be cropped if they are shown inside a deeply nested parent with restricted styling.

Context Menus: To make sure they are completely visible and unhindered by parent elements, menus that show up when you right-click frequently need to render outside of the standard flow.

According to the wrapper components can offer a default layout for displaying child components a valuable pattern for template pages and modals. The modern and suggested method is ReactDOM.createPortal since it preserves the React component tree hierarchy for event propagation and context, even if the actual DOM placement is different. In contrast, older examples might use ReactDOM.render to a different DOM node directly to achieve a similar visual effect. This enables consistent event processing since events from within the portal continue to bubble up to the parent component via the React tree.

Code Example:

Let’s look at a real-world example, such putting in place a timeout alert modal like the one covered in the material. This may have been accomplished in earlier React apps by using ReactDOM.render() to render a new React component straight into a distinct DOM element. Portals, on the other hand, are declared inside the render method of your component, but their destination is an external DOM node.

import React, { useState, useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
const App = () => {
  const [open, setOpen] = useState(false);
  return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 dark:bg-gray-900 text-gray-900 dark:text-white p-4">
      <h1 className="text-3xl font-bold mb-4">React Modal Example</h1>
      <button
        onClick={() => setOpen(true)}
        className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-6 rounded-full shadow-lg transition"
      >
        Open Modal
      </button>
      <Modal isOpen={open} onClose={() => setOpen(false)}>
        <h2 className="text-xl font-bold mb-4">Welcome to the Modal!</h2>
        <p className="mb-6">This content is rendered using a React Portal.</p>
        <div className="flex justify-end">
          <button
            onClick={() => setOpen(false)}
            className="bg-gray-300 hover:bg-gray-400 dark:bg-gray-700 text-gray-800 dark:text-white font-bold py-2 px-4 rounded-full"
          >
            Close Modal
          </button>
        </div>
      </Modal>
      <div id="modal-root" />
    </div>
  );
};
const Modal = ({ children, isOpen, onClose }) => {
  const el = useRef(document.createElement('div'));
  const modalRootRef = useRef(null);
  useEffect(() => {
    let root = document.getElementById('modal-root') || document.body.appendChild(Object.assign(document.createElement('div'), {id:'modal-root'}));
    modalRootRef.current = root;
    root.appendChild(el.current);
    return () => root.removeChild(el.current);
  }, []);
  if (!isOpen || !modalRootRef.current) return null;
  return ReactDOM.createPortal(
    <div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50 p-4" onClick={e => e.target.classList.contains('fixed') && onClose()}>
      <div className="relative bg-white dark:bg-gray-800 p-8 rounded-lg shadow-xl max-w-xl w-full">
        {children}
        <button onClick={onClose} className="absolute top-4 right-4 text-gray-400 hover:text-gray-600">
          <svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12"/>
          </svg>
        </button>
      </div>
    </div>,
    el.current
  );
};
export default App;

Output:

React Modal Example

Open Modal
Welcome to the Modal!
This content is rendered using a React Portal.
Close Modal

In this example:

The rendering of the Modal component is controlled by the isModalOpen state. Although the Modal component is technically specified within the div.wrapper of the App component, clicking “Open Modal” sets isModalOpen to true, causing the Modal component to render its content into the #modal-root div. By selecting “Close” within the modal calls handleCloseModal, the modal is hidden and isModalOpen is set to false.aa

It’s easier to manage than manually handling DOM manipulations and event listeners because it ensures that the modal’s content is rendered independently in the DOM but still inherits React context and events (like the “Close” button’s onClick) bubble up through the React component tree. It also simplifies keyboard focus, which is crucial for modal accessibility.

Conclusion

React.js Portals, in summary, offer a sophisticated method of rendering components outside of their parent DOM hierarchy while preserving their position within the React component tree. For user interface elements like modals, tooltips, and popovers that need to visually transcend the style restrictions of their container (such as overflow or z-index) without interfering with event bubbling or context sharing, this method is perfect. Developers may eliminate manual DOM manipulation by utilising ReactDOM.createPortal, which makes their code more readable, cleaner, and easier to maintain. Portals make sure that content acts like any other React child completely integrated with state, props, and event handling even if it is mounted somewhere else in the DOM.

Kowsalya
Kowsalya
Hi, I'm Kowsalya a B.Com graduate and currently working as an Author at Govindhtech Solutions. I'm deeply passionate about publishing the latest tech news and tutorials that bringing insightful updates to readers. I enjoy creating step-by-step guides and making complex topics easier to understand for everyone.
Index