Modal
Accessible dialog component with focus trap and keyboard navigation.
Installation
npx vayu-ui init #one time onlynpx vayu-ui add modalnpx vayu-ui add -t modal #with test case needsUsage
Modal Component
Accessible dialog component with focus trap, keyboard navigation, and compound component API.
1. Uncontrolled Modal
State is managed internally. Use Modal.Trigger to open.
2. Controlled Modal
Control the modal state externally for programmatic opening.
3. Form Modal
Modal containing a form with proper label associations.
4. Destructive Action
Confirmation modal for destructive actions.
5. Size Options
Different modal sizes for different content needs.
6. Configuration Options
Disable overlay click or escape key closing.
<Modal>
<Modal.Trigger>Open Modal</Modal.Trigger>
<Modal.Content>
<Modal.Header>
<div>
<Modal.Title>Modal Title</Modal.Title>
<Modal.Description>This is a description.</Modal.Description>
</div>
<Modal.Close />
</Modal.Header>
<Modal.Body>
<p>This is the modal body content.</p>
</Modal.Body>
<Modal.Footer>
<Modal.Close>Cancel</Modal.Close>
<button>Confirm</button>
</Modal.Footer>
</Modal.Content>
</Modal>Anatomy
import { Modal } from 'vayu-ui';
export default () => (
<Modal>
<Modal.Trigger>Trigger</Modal.Trigger>
<Modal.Overlay />
<Modal.Content>
<Modal.Header>
<Modal.Title>Title</Modal.Title>
<Modal.Description>Description</Modal.Description>
<Modal.Close>Close Icon</Modal.Close>
</Modal.Header>
<Modal.Body>Body content</Modal.Body>
<Modal.Footer>
<Modal.Close>Close Button</Modal.Close>
</Modal.Footer>
</Modal.Content>
</Modal>
);Accessibility
- Keyboard support:
Tabmoves focus within the modal.Esccloses the modal (can be disabled). - ARIA attributes: Uses
role="dialog"orrole="alertdialog". Connectsaria-labelledbyto theModal.Titleandaria-describedbyto theModal.Description. - Focus behavior: Traps focus within the active modal. Returns focus to the trigger element when closed. Auto-focuses the first focusable element or content when opened.
Screen reader behavior
Screen readers will announce the modal as a dialog, reading the title and description as soon as it opens. Since focus is trapped, users cannot accidentally interact with background elements while the modal is active.
Component Folder Structure
Modal/
├── Modal.tsx
├── ModalTrigger.tsx
├── ModalOverlay.tsx
├── ModalContent.tsx
├── ModalHeader.tsx
├── ModalBody.tsx
├── ModalFooter.tsx
├── ModalTitle.tsx
├── ModalDescription.tsx
├── ModalClose.tsx
├── index.ts
├── types.ts
└── README.mdProps
Modal
| Prop | Type | Description |
|---|---|---|
open | boolean | The controlled open state of the modal. |
onOpenChange | (open: boolean) => void | Event handler called when the open state changes. |
defaultOpen | boolean | The default open state when initially rendered. |
size | "sm" | "md" | "lg" | "xl" | "full" | The size of the modal width. Default: "md". |
closeOnOverlayClick | boolean | Whether clicking the overlay closes the modal. Default: true. |
closeOnEscape | boolean | Whether pressing Escape closes the modal. Default: true. |
Modal.Trigger
| Prop | Type | Description |
|---|---|---|
asChild | boolean | Change the default rendered element for the one passed as a child. |
Modal.Overlay
No meaningful props. Inherits HTMLDivElement attributes.
Modal.Content
No meaningful props. Inherits HTMLDivElement attributes.
Modal.Header
No meaningful props. Inherits HTMLDivElement attributes.
Modal.Body
No meaningful props. Inherits HTMLDivElement attributes.
Modal.Footer
No meaningful props. Inherits HTMLDivElement attributes.
Modal.Title
No meaningful props. Inherits HTMLHeadingElement attributes.
Modal.Description
No meaningful props. Inherits HTMLParagraphElement attributes.
Modal.Close
| Prop | Type | Description |
|---|---|---|
asChild | boolean | Change the default rendered element for the one passed as a child. |