Portals

Using ReactDOM.createPortal:

const modalRoot = document.getElementById("modal-root") as HTMLElement;
// assuming in your html file has a div with id 'modal-root';
export class Modal extends React.Component {
el: HTMLElement = document.createElement("div");
componentDidMount() {
modalRoot.appendChild(this.el);
}
componentWillUnmount() {
modalRoot.removeChild(this.el);
}
render() {
return ReactDOM.createPortal(this.props.children, this.el);
}
}

View in the TypeScript Playground

Using hooks

Same as above but using hooks

import React, { useEffect, useRef } from "react";
import { createPortal } from "react-dom";
const modalRoot = document.querySelector("#modal-root") as HTMLElement;
const Modal: React.FC<{}> = ({ children }) => {
const el = useRef(document.createElement("div"));
useEffect(() => {
// We assume `modalRoot` exists with '!'
modalRoot!.appendChild(el.current);
return () => void modalRoot!.removeChild(el.current);
}, []);
return createPortal(children, el.current);
};
export default Modal;

View in the TypeScript Playground

Modal Component Usage Example:

function App() {
const [showModal, setShowModal] = React.useState(false);
return (
<div>
// you can also put this in your static html file
<div id="modal-root"></div>
{showModal && (
<Modal>
<div
style={{
display: "grid",
placeItems: "center",
height: "100vh",
width: "100vh",
background: "rgba(0,0,0,0.1)",
zIndex: 99,
}}
>
I'm a modal!{" "}
<button
style={{ background: "papyawhip" }}
onClick={() => setShowModal(false)}
>
close
</button>
</div>
</Modal>
)}
<button onClick={() => setShowModal(true)}>show Modal</button>
// rest of your app
</div>
);
}
Context of Example

This example is based on the Event Bubbling Through Portal example of React docs.