πΌ React hook for Modals
Simple, lightweight hook for Modals/Dialogs.
This hook is also isomorphic, meaning it works with SSR (server side rendering).
- SSR (server side rendering) support
- TypeScript support
- 2 dependencies (use-ssr, react-useportal)
- Built in state
yarn add use-react-modal or npm i -S use-react-modal
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> ) </> ) }
import useModal, { Provider } from 'use-react-modal' const MyComponent = () => { const { isOpen, openModal, Modal } = useModal() return ( <> <button onClick={openModal}>Open Me!</button> {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)'> <MyComponent /> </Provider> )
Make sure you are passing the html synthetic event to the openModal
and toggleModal
. i.e. onClick={e => openModal(e)}
If for some reason, you don't want to pass around the event
to openModal
or toggleModal
, you can use a targetRef
like this.
import useModal from 'use-react-modal' const App = () => { const { targetRef, openModal, closeModal, isOpen, Modal } = useModal() return ( <> {/* see below how I don't have to pass the event if I use the ref */} <button ref={targetRef} onClick={() => openModal()}> Open Modal </button> {isOpen && ( <Modal> <p> <button onClick={closeModal}>Close me!</button>, hit ESC or Cool Modal π </p> </Modal> )} </> ) }
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 . |
const { openModal, closeModal, toggleModal, isOpen, Modal, // 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 to open the modal targetRef, // this allows you to interact directly with the backdrop/overlay backdropRef, // this allows you to interact directly with the modal modalRef, } = useModal({ // sets the color of the backdrop, if nothing is set, the backdrop will be transparent unless it's set in the Provider // setting to `null` removes any background set in the `Provider` background: 'rgba(0, 0, 0, 0.5)', 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 }) {} })
Can also do array destructuring
const [openModal, closeModal, isOpen, Modal, toggleModal, targetRef, portalRef, modalRef] = useModal()
- animations π
- React Native support. 1 2 3 4 5 Probably going to have to add a
Provider
... - add correct return types
- tests (priority)
- potential syntax ideas
// then you can change the order of the array destructuring syntax <Provider order={['Modal', 'openModal']} /> // CustomModal, CustomCloseButton <Provider Modal={CustomModal} CloseButton={CustomClostButton} /> const { Modal, CloseButton } = useProvider() // customize the modal animations const { Modal } = useModal({ onOpen({ modal }) { modal.current.style.cssText = ` /* do some animation in */ ` }, onClose({ modal }) { modal.current.style.cssText = ` /* do some animation out */ ` } }) // customize the modal animations idea 2 const { Modal } = useModal({ animateIn: ` /* css for animating in */ `, animateOut: ` /* css for animating out */ `, }) // customize the modal animations idea 3 // maybe have some predefined options? const { Modal } = useModal({ animate: 'fade-in-out', // 'slide-in-top', etc... }) // check out http://reactcommunity.org/react-modal/styles/transitions.html