React Cool Portal
This is a React hook for Portals. It helps you render children into a DOM node that exists outside the DOM hierarchy of the parent component. From now on you will never need to struggle with modals, dropdowns, tooltips etc. Check the features section out to learn more. Hope you guys 👍🏻 it.
❤️ it? ⭐️ it on GitHub or Tweet about it.

Live Demo

⚡️ Try yourself: https://react-cool-portal.netlify.com
Features
Requirement
To use react-cool-portal
, you must use react@16.8.0
or greater which includes hooks.
Installation
This package is distributed via npm.
$ yarn add react-cool-portal
$ npm install --save react-cool-portal
Usage
Here are some minimal examples of how does it work. You can learn more about it by checking the API out.
Basic Use Case
Inserts an element or component into the a different location in the DOM.
import React from 'react';
import usePortal from 'react-cool-portal';
const App = () => {
const { Portal } = usePortal();
return (
<div>
<Portal>
<p>
Wow! I am rendered outside the DOM hierarchy of my parent component.
</p>
</Portal>
</div>
);
};
By default, the children of portal is rendered into <div id="react-cool-portal">
of <body>
. You can specify the DOM element you want through the containerId
option.
import React from 'react';
import usePortal from 'react-cool-portal';
const App = () => {
const { Portal } = usePortal({ containerId: 'my-portal-root' });
return (
<div>
<Portal>
<p>Now I am rendered into the specify element (id="my-portal-root").</p>
</Portal>
</div>
);
};
Note: If the container element doesn't exist, we will create it for you.
Use with State
react-cool-portal
provides many useful features, which enable you to build a component with state. For instance, modal, dropdown, tooltip and so on.

import React from 'react';
import usePortal from 'react-cool-portal';
const App = () => {
const { Portal, isShow, show, hide, toggle } = usePortal({
defaultShow: false,
onShow: e => {
},
onHide: e => {
}
});
return (
<div>
<button onClick={show}>Open Modal</button>
<button onClick={hide}>Close Modal</button>
<button onClick={toggle}>{isShow ? 'Close' : 'Open'} Modal</button>
<Portal>
<div class="modal" tabIndex={-1}>
<div
class="modal-dialog"
role="dialog"
aria-labelledby="modal-label"
aria-modal="true"
>
<div class="modal-header">
<h5 id="modal-label" class="modal-title">
Modal title
</h5>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
</div>
</div>
</Portal>
</div>
);
};
🧹 When no element in the container, we will remove it for you to avoid DOM mess.
The above example shows how easy you can handle the visibility of your component. You may ask how to handle the visibility with animations? No worries, you can disable the built-in show/hide
functions by setting the internalShowHide
option as false
then handling the visibility of your component via the isShow
state.

import React from 'react';
import usePortal from 'react-cool-portal';
const App = () => {
const { Portal, isShow, show, hide, toggle } = usePortal({
defaultShow: false,
internalShowHide: false,
onShow: e => {
},
onHide: e => {
}
});
return (
<div>
<button onClick={show}>Open Modal</button>
<button onClick={hide}>Close Modal</button>
<button onClick={toggle}>{isShow ? 'Close' : 'Open'} Modal</button>
<Portal>
<div
// Now you can use the "isShow" state to handle the CSS animations
class={`modal${isShow ? ' modal-open' : ''}`}
tabIndex={-1}
>
<div
class="modal-dialog"
role="dialog"
aria-labelledby="modal-label"
aria-modal="true"
>
<div class="modal-header">
<h5 id="modal-label" class="modal-title">
Modal title
</h5>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
</div>
</div>
</Portal>
</div>
);
};
Besides that, you can also handle the visibility of your component via React animation events or translation events like what I did for the demo app.
Build Your Customized Hook
Are you tired to write the same code over and over again? It's time to build your own hook based on react-cool-portal
then use it wherever you want.
import React, { useCallback } from 'react';
import usePortal from 'react-cool-portal';
const useModal = (options = {}) => {
const { Portal, isShow, ...rest } = usePortal({
...options,
defaultShow: false,
internalShowHide: false
});
const Modal = useCallback(
({ children }) => (
<Portal>
<div class={`modal${isShow ? ' modal-open' : ''}`} tabIndex={-1}>
{children}
</div>
</Portal>
),
[]
);
return { Modal, isShow, ...rest };
};
const App = () => {
const { Modal, show, hide } = useModal();
return (
<div>
<button onClick={show}>Open Modal</button>
<button onClick={hide}>Close Modal</button>
<Modal>
<div
class="modal-dialog"
role="dialog"
aria-labelledby="modal-label"
aria-modal="true"
>
<div class="modal-header">
<h5 id="modal-label" class="modal-title">
Modal title
</h5>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
</div>
</Modal>
</div>
);
};
API
const return = usePortal(parameter);
Return object
It's returned with the following properties.
Key | Type | Default | Description |
---|
Portal | component | | Renders children into a DOM node that exists outside the DOM hierarchy of the parent component. |
isShow | boolean | false | The show/hide state of portal. |
show | function | | To show the portal or set the isShow as true . |
hide | function | | To hide the portal or set the isShow as false . |
toggle | function | | To toggle (show/hide) the portal or set the isShow as true/false . |
Parameter object (optional)
When use react-cool-portal
you can configure the following options via the parameter.
Key | Type | Default | Description |
---|
containerId | string | react-cool-portal | You can specify the container of portal you want by setting it as the id of the DOM element. |
defaultShow | boolean | true | The initial show/hide state of the portal. |
clickOutsideToHide | boolean | true | Hide the portal by clicking outside of it. |
escToHide | boolean | true | Hide the portal by pressing ESC key. |
internalShowHide | boolean | true | Enable/disable the built-in show/hide portal functions, which gives you a flexible way to handle your portal. |
onShow | function | | Triggered when portal is shown or the isShow set to true . |
onHide | function | | Triggered when portal is hidden or the isShow set to false . |
Contributors ✨
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!