Skip to main content
On this page

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@latest
Includes @ninna-ui/core. CSS setup required.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.

Live preview

Sizes

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

Live preview

Centered

Toggle vertical centering of the modal dialog.

Live preview

Controlled

Control the modal open state via React state.

Live preview

Modal is closed

Prevent Close

Disable overlay click and Escape key to create persistent dialogs.

Live preview

With Close Button

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

Live preview

Long Content

Modal body scrolls automatically when content overflows.

Live preview

With Description

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

Live preview

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