Skip to main content
ninna-ui

Modal

A dialog window that appears above the main content with an overlay backdrop.

import { Modal } from "@ninna-ui/overlays"
pnpm add @ninna-ui/overlays

Requires @ninna-ui/core (auto-installed) + CSS setup.

View source

Usage

Import and use the Modal component in your application.

import { Modal } from "@ninna-ui/overlays";
import { Button , Code } from "@ninna-ui/primitives";
export default function Example() {
return (
<Modal>
<Modal.Trigger asChild>
<Button>Open Modal</Button>
</Modal.Trigger>
<Modal.Content>
<Modal.Header>Title</Modal.Header>
<Modal.Body>Content here</Modal.Body>
<Modal.Footer>
<Modal.Close asChild>
<Button variant="ghost">Cancel</Button>
</Modal.Close>
<Button>Confirm</Button>
</Modal.Footer>
</Modal.Content>
</Modal>
);
}

Basic

A basic modal dialog with header, body, and footer.

Sizes

Modal supports xs, sm, md, lg, xl, and full sizes.

Centered

Toggle vertical centering of the modal dialog.

Controlled

Control the modal open state via React state.

Modal is closed

Prevent Close

Disable overlay click and Escape key to create persistent dialogs.

With Close Button

Add a close icon button in the corner using Modal.Close without asChild.

Long Content

Modal body scrolls automatically when content overflows.

With Description

Add an accessible description to the modal for better screen reader support.

API Reference

Complete list of props for the Modal component and its sub-components.

Modal (Root)

PropTypeDefaultDescription
children*ReactNode-Modal content (Trigger, Content, etc.)
openboolean-Controlled open state
defaultOpenbooleanfalseDefault open state (uncontrolled)
onOpenChange(open: boolean) => void-Callback when open state changes
modalbooleantrueWhether the modal blocks interaction with the rest of the page

Modal.Content

PropTypeDefaultDescription
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full''md'Size of the modal content panel
centeredbooleantrueWhether the modal is vertically centered
descriptionstring-Accessible description for the modal. Rendered as sr-only when provided.
closeOnOverlayClickbooleantrueWhether clicking the overlay closes the modal
closeOnEscapebooleantrueWhether pressing Escape closes the modal
onEscapeKeyDown(event: KeyboardEvent) => void-Callback when Escape key is pressed
onPointerDownOutside(event: Event) => void-Callback when pointer clicks outside content
onInteractOutside(event: Event) => void-Callback when focus moves outside content
classNamestring-Additional CSS classes

Modal.Trigger

PropTypeDefaultDescription
asChildbooleanfalseRender as child element instead of wrapping button

Modal.Close

PropTypeDefaultDescription
asChildbooleanfalseRender as child element instead of default close button

Accessibility

  • Uses role="dialog" with aria-modal="true"
  • Focus is trapped inside the modal when open
  • Focus returns to the trigger element when the modal is closed
  • Escape key closes the modal by default (configurable)
  • Overlay click closes the modal by default (configurable)
  • Header content is automatically used as the dialog label