VayuUI

Modal

Accessible dialog component with focus trap and keyboard navigation.

Installation

npx vayu-ui init #one time only
npx vayu-ui add modal
npx vayu-ui add -t modal #with test case needs

Usage

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: Tab moves focus within the modal. Esc closes the modal (can be disabled).
  • ARIA attributes: Uses role="dialog" or role="alertdialog". Connects aria-labelledby to the Modal.Title and aria-describedby to the Modal.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.md

Props

PropTypeDescription
openbooleanThe controlled open state of the modal.
onOpenChange(open: boolean) => voidEvent handler called when the open state changes.
defaultOpenbooleanThe default open state when initially rendered.
size"sm" | "md" | "lg" | "xl" | "full"The size of the modal width. Default: "md".
closeOnOverlayClickbooleanWhether clicking the overlay closes the modal. Default: true.
closeOnEscapebooleanWhether pressing Escape closes the modal. Default: true.

Modal.Trigger

PropTypeDescription
asChildbooleanChange 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

PropTypeDescription
asChildbooleanChange the default rendered element for the one passed as a child.

On this page