Open modals and confirm dialogs from code, without a Modal and a visible state in every page. Wrap the app once in ModalsProvider, then call useModals() where you need a modal, such as an event handler.
open shows a modal with a title, a subtitle and any content. It returns an id.
openConfirm is an alert dialog with a cancel and a confirm action. Both close it unless you set closeOnConfirm or closeOnCancel to false.
Modals stack, and the last one opened is on top. closeAll closes every layer at the end of a flow.
| Attribute | Description | Type | Accepted values | Default |
|---|---|---|---|---|
| labels | default texts of the confirm and cancel actions | { confirm?: string; cancel?: string } | - | Confirm, Cancel |
| children | your app | ReactNode | - | - |
const modals = useModals()
modals.open(options) // returns the id
modals.openConfirm(options) // returns the id
modals.update(id, options) // changes an open modal
modals.close(id) // closes one
modals.closeAll() // closes every one
type OpenModalOptions = {
id?: string // a new modal with the same id replaces the old one
title?: ReactNode
subtitle?: ReactNode
children?: ReactNode
onClose?: () => void // the user closed it: Escape, the backdrop or an action
// ...and any prop of Modal, such as keyboard or disableBackdropClick
}
type ConfirmModalOptions = OpenModalOptions & {
labels?: { confirm?: string; cancel?: string }
onConfirm?: () => void
onCancel?: () => void
closeOnConfirm?: boolean // true
closeOnCancel?: boolean // true
confirmProps?: Partial<ModalActionProps>
cancelProps?: Partial<ModalActionProps>
}
ModalsProvider renders no element of its own, so it has no ref.
Every modal is a Modal, so it traps the focus and closes with Escape. A confirm dialog has role="alertdialog" and is named by its title.
useModals throws when it is used outside ModalsProvider, so a missing provider is caught at once.