Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
react-cool-portal
Advanced tools
React hook for Portals, which renders modals, dropdowns, tooltips etc. to or else.
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.
⚡️ Try yourself: https://react-cool-portal.netlify.app
<body>
or a specified DOM element.react
and react-dom
.To use react-cool-portal
, you must use react@16.8.0
or greater which includes hooks.
This package is distributed via npm.
$ yarn add react-cool-portal
# or
$ npm install --save react-cool-portal
Here are some minimal examples of how does it work. You can learn more about it by checking the API out.
Inserts an element or component into a different location in the DOM.
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 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.
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 usePortal from "react-cool-portal";
const App = () => {
const { Portal, isShow, show, hide, toggle } = usePortal({
defaultShow: false, // The default visibility of portal, default is true
onShow: (e) => {
// Triggered when portal is shown
// The event object will be the parameter of `show(e?)`
},
onHide: (e) => {
// Triggered when portal is hidden
// The event object will be the parameter of `hide(e?)`, it maybe MouseEvent (on clicks outside) or KeyboardEvent (press ESC key)
},
});
return (
<div>
<button onClick={show}>Open Modal</button>
<button onClick={hide}>Close Modal</button>
<button onClick={toggle}>{isShow ? "Close" : "Open"} Modal</button>
<Portal>
<div className="modal" tabIndex={-1}>
<div
className="modal-dialog"
role="dialog"
aria-labelledby="modal-label"
aria-modal="true"
>
<div className="modal-header">
<h5 id="modal-label" className="modal-title">
Modal title
</h5>
</div>
<div className="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. However, the feature can be turn off via the autoRemoveContainer option.
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 to false
then handling the visibility of your component via the isShow
state.
import usePortal from "react-cool-portal";
const App = () => {
const { Portal, isShow, show, hide, toggle } = usePortal({
defaultShow: false,
internalShowHide: false, // Disable the built-in show/hide portal functions, default is true
onShow: (e) => {
// Triggered when `isShow` is set to true
},
onHide: (e) => {
// Triggered when `isShow` is set to false
},
});
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
className={`modal${isShow ? " modal-open" : ""}`}
tabIndex={-1}
>
<div
className="modal-dialog"
role="dialog"
aria-labelledby="modal-label"
aria-modal="true"
>
<div className="modal-header">
<h5 id="modal-label" className="modal-title">
Modal title
</h5>
</div>
<div className="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 transition events like what I did for the demo app.
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 { useCallback } from "react";
import usePortal from "react-cool-portal";
// Customize your hook based on react-cool-portal
const useModal = (options = {}) => {
const { Portal, isShow, ...rest } = usePortal({
...options,
defaultShow: false,
internalShowHide: false,
});
const Modal = useCallback(
({ children }) => (
<Portal>
<div className={`modal${isShow ? " modal-open" : ""}`} tabIndex={-1}>
{children}
</div>
</Portal>
),
[isShow]
);
return { Modal, isShow, ...rest };
};
// Use it wherever you want
const App = () => {
const { Modal, show, hide } = useModal();
return (
<div>
<button onClick={show}>Open Modal</button>
<button onClick={hide}>Close Modal</button>
<Modal>
<div
className="modal-dialog"
role="dialog"
aria-labelledby="modal-label"
aria-modal="true"
>
<div className="modal-header">
<h5 id="modal-label" className="modal-title">
Modal title
</h5>
</div>
<div className="modal-body">
<p>Modal body text goes here.</p>
</div>
</div>
</Modal>
</div>
);
};
One problem of the above example is that CSS transition/animation will be cut off due to the re-creating of the Portal
component. So if you want to apply transitions or animations to the wrapped element of the customized hook. The isShow
need to be passed from the props.
const useModal = (options = {}) => {
const { Portal, ...rest } = usePortal({
...options,
defaultShow: false,
internalShowHide: false,
});
const Modal = useCallback(
// Pass the `isShow` from props to prevent CSS transition/animation to be cut off
({ isShow, children }) => (
<Portal>
<div className={`modal${isShow ? " modal-open" : ""}`} tabIndex={-1}>
{children}
</div>
</Portal>
),
[]
);
return { Modal, ...rest };
};
ESC or click outside to hide is an out-of-box feature of react-cool-portal
. However, you can conditionally hide the portal based on the presence or absence of an element. Here we take a nested modal as the example:
import usePortal from "react-cool-portal";
const App = () => {
const [showChildModal, setShowChildModal] = useState(false);
const { Portal: ChildModal, show } = usePortal({ defaultShow: false });
const { Portal: ParentModal } = usePortal({
// Provide the class name of the child modal, so the parent modal will only be hidden when the child modal is hidden
escToHide: ["child-modal"],
// The same as `escToHide`
clickOutsideToHide: ["child-modal"],
});
return (
<div>
<ParentModal>
<div>
<p>I'm parent modal.</p>
<button onClick={show}>Open Child Modal</button>
<ChildModal>
<div className="child-modal">
<p>I'm child modal.</p>
</div>
</ChildModal>
</div>
</ParentModal>
</div>
);
};
const returnObj = usePortal(parameterObj);
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 to true . | |
hide | function | To hide the portal or set the isShow to false . | |
toggle | function | To toggle (show/hide) the portal or set the isShow to true/false . |
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 your own container id from an existing DOM element or let this hook automatically creates it for you. |
autoRemoveContainer | boolean | true | Enable/disable the built-in automatically remove container function. |
defaultShow | boolean | true | The initial show/hide state of the portal. |
clickOutsideToHide | boolean | array | true | Hide the portal by clicking outside of it. For conditionally hide please see the example. |
escToHide | boolean | array | true | Hide the portal by pressing ESC key. For conditionally hide please see the example. |
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 . |
💡 If you have written any blog post or article about
react-cool-portal
, please open a PR to add it here.
Thanks goes to these wonderful people (emoji key):
Welly 💻 📖 🚧 | Dawid Karabin 📖 | Honza Stepanovsky 🐛 |
This project follows the all-contributors specification. Contributions of any kind welcome!
FAQs
React hook for Portals, which renders modals, dropdowns, tooltips etc. to or else.
We found that react-cool-portal demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.