Modal
Modal components display content in a layer above the main page. Use them for confirmations, forms, detailed information, or any interaction that requires focused user attention.
Modal Playground
Installation
You can add the modal component to your project manually:
Install the following dependencies:
npm install class-variance-authority clsx tailwind-merge @phosphor-icons/react @react-aria/button @react-aria/focus @react-aria/interactionsCopy and paste the following code into your project.
Update the import paths to match your project setup.
Update the import aliases (e.g. @/components, @/utils) in the copied files to match your project's path configuration.
Basic Usage
A simple modal with header, body, and footer:
import { useState } from 'react';
import { Modal } from '@versaui/ui/components/Modal';
import { Button } from '@versaui/ui/components/Button';
function Example() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<Button onClick={() => setIsOpen(true)}>Open Modal</Button>
<Modal open={isOpen} onOpenChange={setIsOpen}>
<Modal.Content>
<Modal.Header title="Confirm Action" />
<Modal.Body>
Are you sure you want to proceed?
</Modal.Body>
<Modal.Footer>
<Button variant="neutral" buttonStyle="subtle" onClick={() => setIsOpen(false)}>
Cancel
</Button>
<Button variant="primary" buttonStyle="filled">
Confirm
</Button>
</Modal.Footer>
</Modal.Content>
</Modal>
</>
);
}Sizes
Five sizes are available — sm, md (default), lg, xl, and full:
<Modal open={isOpen} onOpenChange={setIsOpen} size="lg">
<Modal.Content>
<Modal.Header title="Large Modal" />
<Modal.Body>Content with more horizontal space.</Modal.Body>
</Modal.Content>
</Modal>| Size | Max Width |
|---|---|
sm | 400px |
md | 560px |
lg | 720px |
xl | 960px |
full | 100vw - 48px |
Header Variants
With Description
Add context with a description below the title:
<Modal.Header
title="Create New Project"
description="Fill in the details to get started"
/>With Icon
Add a leading icon for visual emphasis:
import { Folder as FolderIcon } from '@phosphor-icons/react';
<Modal.Header
title="Create New Project"
icon={<FolderIcon />}
/>Hide Close Button
For modals that require explicit action:
<Modal.Header
title="Terms & Conditions"
showCloseButton={false}
/>Footer with Left Content
Add metadata, checkboxes, or other content to the left side of the footer:
import { Checkbox } from '@versaui/ui/components/Checkbox';
<Modal.Footer
leftContent={<Checkbox label="Don't show again" />}
>
<Button variant="primary" buttonStyle="filled">Continue</Button>
</Modal.Footer>Dismiss Behavior
Control how the modal can be closed:
// Prevent backdrop clicks from closing
<Modal
open={isOpen}
onOpenChange={setIsOpen}
closeOnBackdrop={false}
>
...
</Modal>
// Prevent ESC key from closing
<Modal
open={isOpen}
onOpenChange={setIsOpen}
closeOnEsc={false}
>
...
</Modal>Scrollable Content
For long content, Modal.Body automatically scrolls while header and footer remain fixed:
<Modal open={isOpen} onOpenChange={setIsOpen}>
<Modal.Content>
<Modal.Header title="Terms of Service" sticky />
<Modal.Body>
{/* Long content here */}
</Modal.Body>
<Modal.Footer sticky>
<Button variant="primary" buttonStyle="filled">Accept</Button>
</Modal.Footer>
</Modal.Content>
</Modal>Accessibility
The Modal component is fully accessible:
- Focus trap: Focus is trapped within the modal while open
- Focus restoration: Returns focus to trigger element on close
- Keyboard navigation:
ESCcloses the modal (configurable) - Screen readers: Proper
aria-labelledbyandaria-describedbyassociations - Body scroll lock: Background scroll is disabled while modal is open
Modal Props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | false | Whether the modal is open (controlled). |
onOpenChange | (open: boolean) => void | — | Called when the open state changes. |
size | 'sm' | 'md' | 'lg' | 'xl' | 'full' | 'md' | Width of the modal. |
closeOnBackdrop | boolean | true | Close when clicking the backdrop. |
closeOnEsc | boolean | true | Close when pressing ESC key. |
children | ReactNode | — | Modal.Content and other children. |
className | string | '' | Additional CSS classes. |
Modal.Header Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | — | Required. Modal title text. |
description | string | — | Optional description below title. |
icon | ReactNode | — | Optional leading icon element. |
showCloseButton | boolean | true | Show the close button. |
sticky | boolean | false | Stick to top when body scrolls. |
Modal.Body Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Body content. |
className | string | '' | Additional CSS classes. |
Modal.Footer Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Action buttons (right-aligned). |
leftContent | ReactNode | — | Left-aligned content. |
sticky | boolean | false | Stick to bottom when body scrolls. |