useModal
Simple, lightweight hook for Modals/Dialogs.
This hook is also isomorphic, meaning it works with SSR (server side rendering).
Features
- SSR (server side rendering) support
- TypeScript support
- 2 dependencies (use-ssr, react-useportal)
- Built in state
Installation
yarn add use-react-modal or npm i -S use-react-modal
Usage
Basic Usage
import useModal from 'use-react-modal'
const App = () => {
const { isOpen, openModal, closeModal, Modal } = useModal()
return (
<>
<button onClick={openModal}>Open Me!</button>
{isOpen && (
<Modal>
<button onClick={closeModal}>close</button>
Whatever you put here will be centered to the middle of the screen.
</Modal>
)
</>
)
}
With Provider
import useModal from 'use-react-modal'
const App = () => {
const { isOpen, openModal, closeModal, Modal } = useModal()
return (
<>
{isOpen && (
<Modal>
Now, whatever you put here will be centered AND have a backdrop
with the color specified in the Provider
</Modal>
)
</>
)
}
const App = () => (
<Provider background='rgba(0, 0, 0, 0.5)'>
This text is portaled into San Francisco!
</Portal>
)
Make sure you are passing the html synthetic event to the openModal
and toggleModal
. i.e. onClick={e => openModal(e)}
Usage with a ref
If for some reason, you don't want to pass around the event
to openModal
or toggleModal
, you can use a ref
like this.
import useModal from 'use-react-modal'
const App = () => {
const { ref, openModal, closeModal, isOpen, Modal } = useModal()
return (
<>
{/* see below how I don't have to pass the event if I use the ref */}
<button ref={ref} onClick={() => openModal()}>
Open Modal
</button>
{isOpen && (
<Modal>
<p>
<button onClick={closePortal}>Close me!</button>, hit ESC or
Cool Modal ?
</p>
</Modal>
)}
</>
)
}
Options
Option | Description |
---|---|
background |
sets the color of the backdrop, if nothing is set, there will be no backdrop |
closeOnOutsideClick |
This will close the modal when not clicking within the modal. Default is true |
closeOnEsc |
This will allow you to hit ESC and it will close the modal. Default is true |
bindTo |
This is the DOM node you want to attach the modal to. By default it attaches to document.body |
isOpen |
This will be the default for the modal being open or closed. Default is false |
onOpen |
This is used to call something when the modal is opened |
onClose |
This is used to call something when the modal is closed |
html event handlers (i.e. onClick ) |
These can be used instead of onOpen . |
Option Usage
const {
openModal,
closeModal,
toggleModal,
isOpen,
Modal,
ref, // if you don't pass an event to openModal, closeModal, or toggleModal, you will need to put this on the element you want to interact with/click
} = useModal({
background: 'rgba(0, 0, 0, 0.5)', // sets the color of the backdrop, if nothing is set, there will be no backdrop
closeOnOutsideClick: true,
closeOnEsc: true,
bindTo, // attach the portal to this node in the DOM
isOpen: false,
// `event` has all the fields that a normal `event` would have such as `event.target.value`, etc.
// with the additional `portal` and `targetEl` added to it as seen in the examples below
onOpen: (event) => {
// can access: event.portal, event.targetEl, event.event, event.target, etc.
},
// `onClose` will not have an `event` unless you pass an `event` to `closePortal`
onClose({ targetEl, event, portal }) {},
// `targetEl` is the element that you either are attaching a `ref` to
// or that you are putting `openPortal` or `togglePortal` or `closePortal` on
// in addition, any event handler such as onClick, onMouseOver, etc will be handled the same
onClick({ targetEl, event, portal }) {}
})
Todos
- [ ] maybe disable scrolling outside of the portal when it is open?
- [ ] React Native support. 1 2 3 4 5 Probably going to have to add a
Provider
... - [ ] add correct return types
- [ ] tests (priority)
- [ ] maybe have a
<Provider order={['Modal', 'openModal']} />
then you can change the order of the array destructuring syntax