Modal
A Centered overlay that requires user interaction before returning to the main interface. It focuses attention on critical information or actions, ideal for confirmations.
Basic
A modal is a pop-up window that demands your attention. You have to deal with it before doing anything else on the page.
Installation
npx shadcn@latest add @intentui/modalComposed components
When you install this component via the CLI, it automatically loads all composed components, so you don’t need to add them individually.
This component comes packed with several components to enhance functionality and provide a seamless experience.
Manual installation
npm i react-aria-componentsAnatomy
import { Button } from "@/components/ui/button"
import {
Modal,
ModalBody,
ModalClose,
ModalContent,
ModalDescription,
ModalFooter,
ModalHeader,
ModalTitle,
ModalTrigger,
} from "@/components/ui/modal"<Modal>
<ModalTrigger>Open Modal</ModalTrigger>
<ModalContent>
<ModalHeader>
<ModalTitle>Modal Title</ModalTitle>
<ModalDescription>Modal Description</ModalDescription>
</ModalHeader>
<ModalBody>Modal Body</ModalBody>
<ModalFooter>
<ModalClose>Close</ModalClose>
<Button>Confirm</Button>
</ModalFooter>
</ModalContent>
</Modal>Alert dialog
Alert dialogs are meant to interrupt the user with a critical message, so use 'em only when it's absolutely necessary. The fix? Set the role to alertdialog, and you're golden.
Notice how the modal is dismissible and the close button is hidden? That's 'cause the role is set to alertdialog.
<ModalOverlay isDismissable={false}/>Controlled
You can control the modal programmatically.
Sizes
The modal is set to lg by default. You can adjust it to any size from the available options.
Blur
If you want to blur the background, you can use isBlurred prop.
Sticky
You can use the ModalBody component to make the modal sticky.
Nested
You can also nest modals. Try open it and confirm!
Header
This setup’s super flexible. If you skip adding ModalTitle and just drop a string as its child, it'll auto-render as the title. Like this:
<ModalHeader>
Title
</ModalHeader>Wanna customize more? Throw in props like title and description for a tailored header:
<ModalHeader title='Title' description='Description' />Triggered by menu
You can also trigger the modal by clicking on a menu item.
It might be a good idea to extract the modal into a separate component for better organization.
interface ModalActionProps {
state: string | null
onOpenChange: () => void
actionType: { description: string; action: () => void; confirmText: string; title: string }
disabled: boolean
}
const ModalAction = (props: ModalActionProps) => (
<ModalContent isOpen={props.state !== null} onOpenChange={props.onOpenChange}>
<ModalHeader>
<ModalTitle>{props.actionType?.title}</ModalTitle>
<ModalDescription>{props.actionType?.description}</ModalDescription>
</ModalHeader>
<ModalFooter>
<ModalClose>Cancel</ModalClose>
<Button
intent={props.state === "ban" ? "danger" : "primary"}
className="min-w-24"
isDisabled={props.disabled}
onPress={props.actionType?.action}
>
{props.disabled ? <Loader variant="spin" /> : props.actionType?.confirmText}
</Button>
</ModalFooter>
</ModalContent>
)Then you can use it like this.
<ModalAction
state={state}
onOpenChange={closeModal}
actionType={actionType(state)}
disabled={loading}
/>With that, now we can modify the actionType function to return the initial state.
const actionType = (t: string | null) => {
const initialsState = {
title: '',
description: '',
confirmText: '',
action: () => {}
}
switch (t) {
case 'delete': ...
case 'ban': ...
case 'restore': ...
default:
return initialsState
}
}