Modal
A Modal component is a dialog that focuses the user’s attention exclusively on an information via a window that is overlaid on primary content.
Import
import {
Modal,
ModalTrigger,
ModalContent,
ModalHeading,
ModalFooter,
ModalBody,
ModalCloseButton
} from "@recastui/react";
Usage
Editable Example
<Modal><ModalTrigger asChild><Button>Open Modal</Button></ModalTrigger><ModalContent><ModalHeading>Modal Title</ModalHeading><ModalCloseButton /><ModalBody>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</ModalBody><ModalFooter><div className='space-x-3'><Button>Main Action</Button><Button variant='ghost'>Secondary Action</Button></div></ModalFooter></ModalContent></Modal>
Return Focus after Modal Closure
Upon closing the Modal, focus reverts to the element that initiated it. Default is true.
Editable Example
<Modal returnFocus={false}><ModalTrigger asChild><Button>Open Modal</Button></ModalTrigger><ModalContent><ModalHeading>Modal Title</ModalHeading><ModalCloseButton /><ModalBody>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</ModalBody><ModalFooter><div className='space-x-3'><Button>Main Action</Button><Button variant='ghost'>Secondary Action</Button></div></ModalFooter></ModalContent></Modal>
Controlled State
Use the open and onOpenChange props to control the modal state externally.
Editable Example
() => {const [isOpen, setIsOpen] = useState(false);return (<><Button onClick={() => setIsOpen(true))>Open Modal</Button><Modal open={isOpen} onOpenChange={setIsOpen}><ModalContent><ModalHeading>Modal Title</ModalHeading><ModalCloseButton /><ModalBody>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</ModalBody><ModalFooter><div className='space-x-3'><Button onClick={() => setIsOpen(false))>Close</Button><Button variant='ghost'>Secondary Action</Button></div></ModalFooter></ModalContent></Modal></>)}
Make modal centered in the screen
By default the modal has a vertical offset of 4rem(64px) which you can change by passing top to the ModalContent. If you need to don’t vertically center the modal, pass the ‘isCentered’ prop. Default is set to false.
Editable Example
<Modal isCentered><ModalTrigger asChild><Button>Open Modal</Button></ModalTrigger><ModalContent><ModalHeading>Modal Title</ModalHeading><ModalCloseButton /><ModalBody>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</ModalBody><ModalFooter><div className='space-x-3'><Button>Main Action</Button><Button variant='ghost'>Secondary Action</Button></div></ModalFooter></ModalContent></Modal>
Modal Sizes
Pass the size prop if you need to adjust the size of the modal. Values can be xs
, sm
, md
, lg
, xl
, or full
. Default is md
.
Editable Example
() => {const [isOpen, setIsOpen] = useState(false);const [size, setSize] = useState('md');const handleSizeClick = (newSize) => {setSize(newSize);setIsOpen(true);};const sizes = ['xs', 'sm', 'md', 'lg', 'xl', 'full'];return (<><div className='grid gap-2 grid-cols-3'>{sizes.map((s) => (<Modal key={s} size={s}><ModalTrigger asChild><Button>Show {s} Modal</Button></ModalTrigger><ModalContent><ModalHeading>Modal Title</ModalHeading><ModalCloseButton /><ModalBody>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</ModalBody><ModalFooter><div className='space-x-3'><Button>Main Action</Button><Button variant='ghost'>Secondary Action</Button></div></ModalFooter></ModalContent></Modal>))}</div></>);}
Props
Modal
Prop | Type | Default | Description |
---|---|---|---|
initialOpen | boolean | false | The initial open state of the Modal (optional). |
open | boolean | - | The open state of the Modal in controlled mode. |
onOpenChange | (open: boolean) => void | - | A callback function for handling open state changes in controlled mode. |
initialFocus | React.RefObject<HTMLElement> | - | Ref to the initial element to focus when the modal opens. |
returnFocus | boolean | true | Return focus to the element that triggered modal to open when the modal closes. |
size | “xs” | “sm” | “md” | “lg” | “xl” | “full” | “md” | The size of the modal. |
isCentered | boolean | false | Whether the modal should be vertically centered. |
children | React.ReactNode | - | Children passed to the subcomponents. |
ModalContent
Prop | Type | Default | Description |
---|---|---|---|
className | string (optional) | - | Additional class names to apply |
overlayClassName | string (optional) | - | Additional class names to apply to the Overlay element |
children | React.ReactNode | - | Children passed to the component. |
ModalTrigger
Prop | Type | Default | Description |
---|---|---|---|
asChild | boolean | false | Children passed to the component. |
className | string (optional) | - | Additional class names to apply |
children | React.ReactNode | - | Children passed to the component. |
ModalTrigger, ModalHeading, ModalBody, ModalFooter & ModalCloseButton
Prop | Type | Description |
---|---|---|
children | React.ReactNode | The children for the subcomponent |
className | string (optional) | Additional class names to apply |
Accessibility
This Modal component has been designed to follow best practices for accessibility:
- Focus is trapped within the modal when it is open.
- Focus is automatically set to the first enabled element or the element specified by
initialFocus
. - When the modal closes, focus returns to the element that was focused before the modal was activated, or the element specified by
finalFocusRef
. - Clicking on the overlay closes the modal.
- Pressing the
Esc
key closes the modal. - Scrolling is blocked on the elements behind the modal.
- The modal is rendered in a portal attached to the end of
document.body
, making it easy to addaria-hidden
to its siblings. aria-modal
is set totrue
on theModalContent
component.aria-labelledby
is set to theid
of theModalHeading
component.aria-describedby
is set to theid
of theModalBody
component.