Skip to content

Instantly share code, notes, and snippets.

@apostolos
Created October 5, 2017 09:35
Show Gist options
  • Save apostolos/ceab2e66dddc85e9fd5a9bc4139ed199 to your computer and use it in GitHub Desktop.
Save apostolos/ceab2e66dddc85e9fd5a9bc4139ed199 to your computer and use it in GitHub Desktop.
// @flow
import * as React from 'react';
import ReactDOM from 'react-dom';
type Props = {
children: React.Node,
containerRef?: (el: ?HTMLElement) => void,
};
/**
* This component detaches its contents and re-attaches them to document.body (using ReactDOM.createPortal).
* Use it when you need to circumvent DOM z-stacking (for dialogs, popovers, etc.).
* Any class names passed to this element will be propagated to the new container element on document.body.
*/
class Portal extends React.Component<Props, void> {
targetElement: HTMLElement | null = null;
render() {
if (this.targetElement === null && document.body) {
this.targetElement = document.body.appendChild(document.createElement('div'));
this.targetElement.className = 'portal';
}
const { containerRef, children, ...rest } = this.props;
// $FlowFixMe
return ReactDOM.createPortal(
<div {...rest} ref={containerRef}>
{children}
</div>,
this.targetElement
);
}
componentWillUnmount() {
if (this.targetElement !== null && document.body) {
document.body.removeChild(this.targetElement);
this.targetElement = null;
}
}
}
export default Portal;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment