How to Implement React Portals in React

React Portals provide a powerful way to render child components into a DOM node that exists outside the DOM hierarchy of the parent component. This article explains the core concept of React Portals, why they are essential for UI elements like modals, tooltips, and dropdowns, and provides a clear, step-by-step guide on how to implement them in your React applications.

Why Use React Portals?

In a standard React application, components render within the DOM hierarchy of their parent components. However, this can cause visual bugs when dealing with CSS properties like z-index, overflow: hidden, or position: absolute. For example, a modal nested deep inside a container with overflow: hidden might get clipped.

React Portals solve this by allowing you to render a component visually on top of everything else (like at the end of the <body> tag) while maintaining its position in the React component tree. This ensures the component still has access to React context, state, and props.

Step 1: Add a Target DOM Node

First, you need to define where the portal should render in your HTML structure. Open your public/index.html file (or your main HTML entry file) and add a new placeholder div next to the main application root.

<body>
  <!-- The main React application -->
  <div id="root"></div>
  
  <!-- The target element for your portal -->
  <div id="portal-root"></div>
</body>

Step 2: Create the Portal Component

To create a portal, use the createPortal function from the react-dom package. This function takes two arguments: the React elements to render (the children) and the DOM element where those elements should be mounted.

Create a reusable Portal component:

import { createPortal } from 'react-dom';

const Portal = ({ children }) => {
  // Select the target DOM node created in Step 1
  const portalRoot = document.getElementById('portal-root');

  // If the target element doesn't exist, return null
  if (!portalRoot) return null;

  // Render the children inside the target DOM node
  return createPortal(children, portalRoot);
};

export default Portal;

Step 3: Implement the Portal in a Component

Now you can use the Portal component to overlay elements like modals. Here is an example of a modal component that uses the portal to render outside the main application DOM structure.

import React, { useState } from 'react';
import Portal from './Portal';

const Modal = ({ isOpen, onClose }) => {
  if (!isOpen) return null;

  return (
    <Portal>
      <div className="modal-overlay" style={overlayStyles}>
        <div className="modal-content" style={modalStyles}>
          <h2>Modal Title</h2>
          <p>This modal is rendered outside the main app root!</p>
          <button onClick={onClose}>Close Modal</button>
        </div>
      </div>
    </Portal>
  );
};

// Simple inline styles for demonstration
const overlayStyles = {
  position: 'fixed',
  top: 0,
  left: 0,
  right: 0,
  bottom: 0,
  backgroundColor: 'rgba(0, 0, 0, 0.7)',
  display: 'flex',
  justifyContent: 'center',
  alignItems: 'center',
  zIndex: 1000,
};

const modalStyles = {
  background: 'white',
  padding: '20px',
  borderRadius: '8px',
  boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',
};

export default Modal;

Step 4: Use the Modal in Your Application

You can now toggle and render the modal from any parent component without worrying about parent container CSS clipping the modal container.

import React, { useState } from 'react';
import Modal from './Modal';

function App() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  return (
    <div style={{ padding: '20px', overflow: 'hidden' }}>
      <h1>My Application</h1>
      <button onClick={() => setIsModalOpen(true)}>Open Modal</button>
      
      {/* Even inside a container with overflow hidden, this renders correctly */}
      <Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
    </div>
  );
}

export default App;

Key Considerations