molecule

Dialog

Modal dialog using native <dialog> with title, description, close button, scrollable body, and action slot.

Overview

The Dialog component provides a modal overlay for focused user interactions. Built on the native <dialog> element, it includes built-in focus trapping, backdrop, and accessibility. Use it for forms, settings panels, detail views, and any content that requires the user's full attention.

import { Dialog, Button } from '@enara-health/ui-react';

const [isOpen, setIsOpen] = useState(false);

<Button onClick={() => setIsOpen(true)}>Open Dialog</Button>

<Dialog
  open={isOpen}
  onOpenChange={setIsOpen}
  title="Edit Profile"
  actions={
    <>
      <Button role="secondary" onClick={() => setIsOpen(false)}>Cancel</Button>
      <Button role="primary" onClick={handleSave}>Save</Button>
    </>
  }
>
  <p>Dialog body content goes here.</p>
</Dialog>

Props

Prop Type Default Description
open boolean - Required. Whether the dialog is visible
onOpenChange (open: boolean) => void - Required. Callback when open state changes
title string - Required. Dialog title displayed in the header
description string - Optional description text below the title
children ReactNode - Required. Body content of the dialog (scrollable)
actions ReactNode - Action buttons rendered in a fixed footer outside the scrollable body
maxWidth number 500 Maximum width of the dialog in pixels
persistent boolean false Prevents closing via Escape or backdrop click
className string - Additional CSS class names

Variants

Basic Dialog

A simple dialog with title and body content.

<Dialog open={isOpen} onOpenChange={setIsOpen} title="Information">
  <p>This is a basic dialog with just a title and content.</p>
</Dialog>

With Description

Add a description below the title for additional context.

<Dialog
  open={isOpen}
  onOpenChange={setIsOpen}
  title="Edit Profile"
  description="Update your personal information below."
  actions={
    <>
      <Button role="secondary" onClick={() => setIsOpen(false)}>Cancel</Button>
      <Button role="primary" onClick={handleSave}>Save</Button>
    </>
  }
>
  <Input label="Name" value={name} onChange={setName} />
  <Input label="Email" value={email} onChange={setEmail} />
</Dialog>

Persistent Mode

Use persistent to prevent closing via Escape or backdrop click. The close button in the header is always available.

<Dialog
  open={isProcessing}
  onOpenChange={setIsProcessing}
  title="Processing..."
  persistent
>
  <Spinner />
  <p>Please wait while we process your request.</p>
</Dialog>

Examples

Form Dialog

Common pattern for editing data in a modal form.

const [isOpen, setIsOpen] = useState(false);

<Dialog
  open={isOpen}
  onOpenChange={setIsOpen}
  title="Edit Patient"
  actions={
    <>
      <Button role="secondary" onClick={() => setIsOpen(false)}>Cancel</Button>
      <Button role="primary" onClick={handleSave}>Save Changes</Button>
    </>
  }
>
  <FormField label="Name">
    <Input value={name} onChange={e => setName(e.target.value)} />
  </FormField>
  <FormField label="Email">
    <Input type="email" value={email} onChange={e => setEmail(e.target.value)} />
  </FormField>
</Dialog>

Scrollable Content

Long content automatically scrolls within the dialog body. Actions stay fixed at the bottom.

<Dialog
  open={isOpen}
  onOpenChange={setIsOpen}
  title="Terms of Service"
  actions={
    <>
      <Button role="secondary" onClick={() => setIsOpen(false)}>Decline</Button>
      <Button role="primary" onClick={handleAccept}>Accept</Button>
    </>
  }
>
  <p>Long content here... (scrolls within the body, actions stay fixed at bottom)</p>
</Dialog>

Custom Width

Override the default max width for wider content.

<Dialog
  open={isOpen}
  onOpenChange={setIsOpen}
  title="Data Preview"
  maxWidth={700}
>
  <Table data={previewData} columns={columns} />
</Dialog>

Accessibility

  • Role: Uses the native <dialog> element which provides built-in role="dialog".
  • Focus Trapping: Native <dialog> traps focus within the dialog while it's open.
  • Keyboard Support: Escape closes the dialog (unless persistent). Tab navigates through focusable elements within.
  • Screen Reader: Title is announced as the dialog label when the dialog opens.
  • WCAG Compliance: Meets AA standards for modal interactions.

Best Practices

  • Use for focused tasks that require user attention — not for simple confirmations (use AlertDialog)
  • Avoid nesting dialogs — replace content or use navigation instead
  • Always provide a clear way to close the dialog
  • Keep dialog content focused on a single task
  • Use persistent sparingly — only when dismissal would cause data loss