import { useLayoutEffect, useState } from 'react' import { createPortal } from 'react-dom' function createWrapperAndAppendToBody(wrapperId: string) { const wrapperElement = document.createElement('div') wrapperElement.setAttribute('id', wrapperId) document.body.appendChild(wrapperElement) return wrapperElement } type PortalComponentProps = { wrapperId: string children?: React.ReactNode } function PortalComponent({ wrapperId = 'react-portal-wrapper', children }: PortalComponentProps): React.ReactPortal | null { const [wrapperElement, setWrapperElement] = useState(null) useLayoutEffect(() => { let element = document.getElementById(wrapperId) let systemCreated = false // if element is not found with wrapperId or wrapperId is not provided, // create and append to body if (!element) { systemCreated = true element = createWrapperAndAppendToBody(wrapperId) } setWrapperElement(element) return () => { // delete the programatically created element if (systemCreated && element && element.parentNode) { element.parentNode.removeChild(element) } } }, [wrapperId]) // wrapperElement state will be null on very first render. if (wrapperElement === null) return null return createPortal(children, wrapperElement) } export default PortalComponent