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>

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

PropTypeDefaultDescription
initialOpenbooleanfalseThe initial open state of the Modal (optional).
openboolean-The open state of the Modal in controlled mode.
onOpenChange(open: boolean) => void-A callback function for handling open state changes in controlled mode.
initialFocusReact.RefObject<HTMLElement>-Ref to the initial element to focus when the modal opens.
returnFocusbooleantrueReturn 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.
isCenteredbooleanfalseWhether the modal should be vertically centered.
childrenReact.ReactNode-Children passed to the subcomponents.

ModalContent

PropTypeDefaultDescription
classNamestring (optional)-Additional class names to apply
overlayClassNamestring (optional)-Additional class names to apply to the Overlay element
childrenReact.ReactNode-Children passed to the component.

ModalTrigger

PropTypeDefaultDescription
asChildbooleanfalseChildren passed to the component.
classNamestring (optional)-Additional class names to apply
childrenReact.ReactNode-Children passed to the component.

ModalTrigger, ModalHeading, ModalBody, ModalFooter & ModalCloseButton

PropTypeDescription
childrenReact.ReactNodeThe children for the subcomponent
classNamestring (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 add aria-hidden to its siblings.
  • aria-modal is set to true on the ModalContent component.
  • aria-labelledby is set to the id of the ModalHeading component.
  • aria-describedby is set to the id of the ModalBody component.
Previous
Link