Sedat Polat
Sedat Polat

Reputation: 1721

How to render child component outside of its parent component (DOM Hierarchy) - React.js

I have a table component which has sticky headers and table body rows contain dopdowns, ellipsis menu and some other complex components. Each row of the table has another table body rows inside and parent rows are also sticky for their child table body rows. Dropdown and ellipsis menu stay behinde the next sticky row. Setting z-index is not enough because of the sticky rows. Only way is to render menus outside of the table and give a greater z-index.

To make the question easier to understand; Let's say render method is like:

return <div id='parent'>
            <input />
            <span id='child'>{value}</span>
       </div>;

I want to render child outside of parent as a result of DOM Hierarchy:

...
<body>
    <div id='parent'> <input /> </div>
    <div id='child'></div>
<body>
...

Upvotes: 3

Views: 7871

Answers (1)

Sedat Polat
Sedat Polat

Reputation: 1721

After a quick search, I found React Portal approach to render child component html outside of the parent component (DOM Hierarchy).

Component:

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


export const FirstPage = () => {

const [value, setValue] = useState('');

return (
    <div id='parent'>
        <input onChange={e => {setValue(e.target.value)}} value={value} />
        <Portal>
            <span id='child'>{value}</span>
        </Portal>
    </div>);
};

Portal.js implementation with React Hooks:

import React, { useEffect, useRef } from "react"
import ReactDOM from 'react-dom';

export const Portal = (props) => {
    const el = useRef(document.createElement('div'));
    useEffect(() => {
        const portal = document.getElementById('portal');
        portal.appendChild(el.current);

        return () => {
            portal.removeChild(el.current);
        };

    }, [props.children]);

    return ReactDOM.createPortal(props.children, el.current);
}

export const PortalDiv = () => <div id='portal'></div>;

App.js:

import React from 'react';
import './App.css';
import { PortalDiv } from './Portal/Portal';
import { FirstPage } from './Pages/FirstPage';

function App() {
  return (
    <div className="App">
      <FirstPage />
      <PortalDiv />
    </div>
  );
}

export default App;

Result:

<div class="App">
    <div id="parent">
        <input value="random text">
    </div>
    <div id="portal">
        <div><span id="child">random text</span></div>
    </div>
</div>

Example on github: https://github.com/sedpol/react-portal

Upvotes: 10

Related Questions