Using React Portals to Render Elements Anywhere in the DOM
Published: 2024-07-09 05:42:41

**Introduction**
React Portals provide a powerful way to render components outside the main DOM hierarchy, allowing for greater flexibility in placing elements. This is particularly useful for creating modals, tooltips, and other components that need to be rendered at a different location in the DOM. In this guide, we will demonstrate how to use React Portals to open and render elements anywhere in your application.

**Prerequisites**
Before we begin, ensure you have a basic understanding of React and functional components. Familiarity with hooks (useState, useEffect) will be beneficial.

**Step 1: Setting Up the Project**
First, create a new React project or navigate to your existing project:

```
npx create-react-app react-portal-tutorial
cd react-portal-tutorial
npm start

```

**Step 2: Creating the Portal Component**
Create a new file PortalComponent.js and add the following code to define a reusable portal component:

```
import React from 'react';
import ReactDOM from 'react-dom';

const PortalComponent = ({ children, containerId }) => {
  const container = document.getElementById(containerId);
  return container ? ReactDOM.createPortal(children, container) : null;
};

export default PortalComponent;

```
**Step 3: Adding the Target Element in the DOM**
Ensure you have an element in your index.html or another component where the portal can render its content. For instance, add this div in your public/index.html:

```
<body>
  <div id="root"></div>
  <div id="header-children"></div> <!-- Target Element for Portal -->
</body>

```


**Step 4: Implementing the Portal in Your Component**
Create a component, App.js, and use the PortalComponent to render content inside the target element (header-children):

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

const App = () => {
  const [isSearch, setIsSearch] = useState(false);
  const [isDelete, setIsDelete] = useState(false);

  const handleCancel = () => {
    setIsSearch(false);
    setIsDelete(false);
  };

  const onDeleteClick = () => setIsDelete(true);
  const onSearchClick = () => setIsSearch(true);

  return (
    <div>
      <h1>React Portal Example</h1>
      <button onClick={onSearchClick}>Search</button>
      <button onClick={onDeleteClick}>Delete</button>
      <div id="header-children"></div>
      <PortalComponent containerId="header-children">
        <div className="gap-5 flex">
          {isSearch || isDelete ? (
            <button
              className="text-xl leading-8 font-semibold text-caribbeangreen"
              onClick={handleCancel}
            >
              Cancel
            </button>
          ) : (
            <HistoryActions
              history={history}
              onDeleteClick={onDeleteClick}
              onSearchClick={onSearchClick}
            />
          )}
        </div>
      </PortalComponent>
    </div>
  );
};

const HistoryActions = ({ history, onDeleteClick, onSearchClick }) => (
  <div>
    <button onClick={onSearchClick}>Search History</button>
    <button onClick={onDeleteClick}>Delete History</button>
  </div>
);

export default App;

```

**Step 5: Styling the Portal Content**
Add necessary styles in your index.css or another CSS file:

```
.gap-5 {
  gap: 1.25rem;
}

.flex {
  display: flex;
}

.text-caribbeangreen {
  color: #00FF7F;
}

.text-xl {
  font-size: 1.25rem;
}

.leading-8 {
  line-height: 2rem;
}

.font-semibold {
  font-weight: 600;
}

```
**Conclusion**
In this tutorial, we've covered how to use React Portals to render components outside the main DOM hierarchy. By following these steps, you can create flexible and powerful UI elements that can be rendered anywhere in your application. This technique is especially useful for components like modals, tooltips, and context menus.

**first file**

```
const headerChildrenRenderer = document.getElementById("header-children");

  {createPortal(
          <div className="gap-5 flex">
            {isSearch || isDelete ? (
              <button
                className="text-xl leading-8 font-semibold text-caribbeangreen"
                onClick={handleCancel}
              >
                Cancel
              </button>
            ) : (
              <HistroyActions
                history={history}
                onDeleteClick={onDeleteClick}
                onSearchClick={onSearchClick}
              />
            )}
          </div>,
          headerChildrenRenderer as HTMLElement
        )}
```

**second file**

```
// ref for when we want to open above element
        <div id='header-children'></div>
```