Modals manager
Manage different types of modals with a single easy to use hook.
Modals manager helps you create consistent and non-conflicting modals throughout your app with minimal boilerplate code.
Source
@saas-ui/modals
- 2.8.9 (latest)
Import
import { ModalsProvider, useModals } from '@saas-ui/react'
Best practises
Do
- Use the same modal type throughout your app for similar actions.
Don't
- Open multiple modals on top of eachother, with exception of alerts.
Usage
Setup provider
Add ModalsProvider
to the root of your project.
import { SaasProvider, ModalsProvider } from '@saas-ui/react'export default function App({ children }) {return (// ...<SaasProvider><ModalsProvider>{children}</ModalsProvider></SaasProvider>// ...)}
Open a modal
open
acccepts all default Modal
properties, more information.
import { Button } from '@chakra-ui/react'import { useModals } from '@saas-ui/react'export default function Page() {const modals = useModals()return (<ButtononClick={() =>modals.open({title: 'Modal',body: 'Body',footer: 'Footer',})}>Open modal</Button>)}
Open a drawer
drawer
acccepts all default Drawer
properties, more information.
import { Button } from '@chakra-ui/react'import { useModals } from '@saas-ui/react'export default function Page() {const modals = useModals()return (<ButtononClick={() =>modals.drawer({title: 'Drawer',body: 'Body',footer: 'Footer',})}>Open drawer</Button>)}
Open a confirm dialog
confirm
acccepts all default AlertDialog
properties, more information.
import { Button } from '@chakra-ui/react'import { useModals } from '@saas-ui/react'export default function Page() {const modals = useModals()return (<ButtoncolorScheme="red"onClick={() =>modals.confirm({title: 'Delete user',body: 'Are you sure you want to delete this user?',confirmProps: {colorScheme: 'red',label: 'Delete',},onConfirm: () => {}, // action})}>Delete user</Button>)}
Custom modals
You can create custom modals, or change the default modals
modal
, drawer
, alert
, confirm
if you desire to use a
different composition or use a different FormDialog implementation.
import { createModals } from '@saas-ui/react'import { FormDialog } from '@saas-ui/forms/zod'const { ModalsProvider, useModals } = createModals({modals: {modal: MyModal,custom: CustomModal,form: FormDialog,},})function App({ children }) {return <ModalsProvider>{children}</ModalsProvider>}function Page() {const modals = useModals()return (<ButtononClick={() =>modals.open({title: 'My modal',body: 'Custom modal',type: 'custom',})}>Open custom modal</Button>)}
Opening multiple modals
By default modals will never open on top of eachother, except for alert dialogs.
This is handled with scopes, opening a modal in the same scope will replace any
other model in that scope that's currently open. When closing the last modal,
the manager will render the previous open modal, unless you use closeAll
.
import { Button } from '@chakra-ui/react'import { useModals } from '@saas-ui/react'export default function Page() {const modals = useModals()const next = () => {const id = modals.open({title: 'Modal step 2',body: 'Step 2',footer: (<><Button onClick={() => modals.close(id)} mr="3">Back</Button><Button onClick={() => modals.closeAll()}>Done</Button></>),})}return (<ButtononClick={() =>modals.open({title: 'Modal step 1',body: 'Step 1',footer: (<><Button onClick={next}>Next</Button></>),})}>Open modal</Button>)}
Prevent a modal from closing
Return false in the onClose
to prevent a modal from closing.
You can also return a Promise
if you need to do some async checks, like below.
Alerts and confirm dialogs can be opened on top of other modals, for example to warn a person that changes might be lost when closing a modal.
import { Button } from '@chakra-ui/react'import { useModals } from '@saas-ui/react'export default function Page() {const modals = useModals()const close = (resolve) => {const id = modals.confirm({title: 'Unsaved changes',body: 'You have unsaved changes, are you sure you want to cancel?',onConfirm: () => {resolve(true)modals.closeAll()},onCancel: () => resolve(false),})}return (<ButtononClick={() => {const id = modals.drawer({title: 'Profile',hideCloseButton: true,body: (<><Property label="Name" value="Eelco" /></>),footer: (<ButtonGroup><Button onClick={() => modals.close(id)}>Cancel</Button><ButtononClick={() => modals.close(id, true)}colorScheme="primary">Save</Button></ButtonGroup>),onClose: ({ force }) => force || new Promise(close),})}}>Open modal</Button>)}
Scopes
The default scopes are modal
and alert
, to open a modal in a different scope you can use the scope
option.
function Page() {const modals = useModals()return (<ButtononClick={() =>modals.open({title: 'Modal',body: (<ButtononClick={() =>modals.open({title: 'Another modal', // this will open in the `modal` scope})}>Open another modal</Button>),scope: 'myscope',})}>Open modal</Button>)}
Accessibility
Keyboard Interaction
Key | Action |
---|---|
Esc | Close the modal or cancel a confirm dialog |
Was this helpful?