Dialog

A modal dialog component for displaying content that requires user interaction, built on Radix UI with smooth animations and accessibility features.

Usage

Basic Dialog

The Dialog component displays content in a modal overlay that requires user interaction.

import { 
  Dialog, 
  DialogTrigger, 
  DialogContent, 
  DialogHeader, 
  DialogTitle, 
  DialogDescription 
} from "@prisma-docs/eclipse";
import { Button } from "@prisma-docs/eclipse";

export function BasicDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Open Dialog</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Welcome</DialogTitle>
          <DialogDescription>
            This is a basic dialog example. Click outside or press escape to close.
          </DialogDescription>
        </DialogHeader>
      </DialogContent>
    </Dialog>
  );
}

Live Example:

Dialog with Footer

Add action buttons in the footer for user interactions:

import { 
  Dialog, 
  DialogTrigger, 
  DialogContent, 
  DialogHeader,
  DialogFooter,
  DialogTitle, 
  DialogDescription,
  DialogClose,
  Button
} from "@prisma-docs/eclipse";

export function DialogWithFooter() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Delete Account</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Are you absolutely sure?</DialogTitle>
          <DialogDescription>
            This action cannot be undone. This will permanently delete your account
            and remove your data from our servers.
          </DialogDescription>
        </DialogHeader>
        <DialogFooter>
          <DialogClose asChild>
            <Button variant="outline">Cancel</Button>
          </DialogClose>
          <Button variant="destructive">Delete Account</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

Live Example:

Form Dialog

Use Dialog for forms and data input:

import { 
  Dialog, 
  DialogTrigger, 
  DialogContent, 
  DialogHeader,
  DialogFooter,
  DialogTitle, 
  DialogDescription,
  Button,
  Input
} from "@prisma-docs/eclipse";

export function FormDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Edit Profile</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Edit profile</DialogTitle>
          <DialogDescription>Make changes to your profile here. Click save when you're done.</DialogDescription>
        </DialogHeader>
        <div className="grid gap-4 py-4">
          <div className="grid grid-cols-4 items-center gap-4">
            <label htmlFor="name" className="text-right text-sm">
              Name
            </label>
            <Input
              id="name"
              defaultValue="Pedro Duarte"
              className="col-span-3 focus-visible:outline-none"
            />
          </div>
          <div className="grid grid-cols-4 items-center gap-4">
            <label htmlFor="username" className="text-right text-sm">
              Username
            </label>
            <Input
              id="username"
              defaultValue="@peduarte"
              className="col-span-3 focus-visible:outline-none"
            />
          </div>
        </div>
        <DialogFooter>
          <Button type="submit">Save changes</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

Live Example:

Controlled Dialog

Control the dialog's open state programmatically:

import { useState } from "react";
import { 
  Dialog, 
  DialogTrigger, 
  DialogContent, 
  DialogHeader,
  DialogFooter,
  DialogTitle, 
  DialogDescription,
  Button
} from "@prisma-docs/eclipse";

export function ControlledDialog() {
  const [open, setOpen] = useState(false);

  const handleSubmit = () => {
    // Perform some action
    console.log("Action performed");
    setOpen(false);
  };

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button>Open Controlled Dialog</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Controlled Dialog</DialogTitle>
          <DialogDescription>
            This dialog's state is controlled by React state.
          </DialogDescription>
        </DialogHeader>
        <DialogFooter>
          <Button variant="outline" onClick={() => setOpen(false)}>
            Cancel
          </Button>
          <Button onClick={handleSubmit}>
            Confirm
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}

Component Props

Dialog

  • open - Controlled open state (boolean, optional)
  • onOpenChange - Callback when open state changes (function, optional)
  • defaultOpen - Default open state for uncontrolled usage (boolean, optional)
  • modal - Whether the dialog is modal (boolean, default: true)
  • children - Dialog components (ReactNode, required)

DialogTrigger

  • asChild - Merge props onto child element instead of rendering a button (boolean, default: false)
  • children - Trigger element (ReactNode, required)

DialogContent

  • className - Additional CSS classes (string, optional)
  • children - Dialog content (ReactNode, required)
  • All standard div props

DialogHeader

  • className - Additional CSS classes (string, optional)
  • children - Header content, typically DialogTitle and DialogDescription (ReactNode, required)

DialogFooter

  • className - Additional CSS classes (string, optional)
  • children - Footer content, typically action buttons (ReactNode, required)

DialogTitle

  • className - Additional CSS classes (string, optional)
  • children - Title text (ReactNode, required)

DialogDescription

  • className - Additional CSS classes (string, optional)
  • children - Description text (ReactNode, required)

DialogClose

  • asChild - Merge props onto child element (boolean, default: false)
  • children - Close button element (ReactNode, required)

Features

  • ✅ Modal overlay with backdrop
  • ✅ Smooth enter/exit animations
  • ✅ Automatic close button (X icon)
  • ✅ Click outside to close
  • ✅ Press Escape to close
  • ✅ Focus trap when open
  • ✅ Scroll lock on body
  • ✅ Keyboard accessible
  • ✅ ARIA compliant
  • ✅ Controlled or uncontrolled
  • ✅ Portal rendering
  • ✅ Based on Radix UI Dialog

Best Practices

  • Always include a DialogTitle for accessibility (required by screen readers)
  • Use DialogDescription to provide additional context
  • Place destructive actions (like delete) on the right side of the footer
  • Use DialogClose with asChild to make buttons closeable
  • Keep dialog content concise and focused
  • Use controlled state when you need to perform actions before closing
  • For forms, consider using the dialog's close functionality after successful submission
  • Limit dialog width for better readability (max-w-lg is the default)

Common Use Cases

The Dialog component is perfect for:

  • Confirmation dialogs - Confirm destructive or important actions
  • Form inputs - Collect user information without navigation
  • Alerts and notifications - Display important messages requiring acknowledgment
  • Content preview - Show detailed information about items
  • Settings and preferences - Quick access to configuration options
  • Login/Signup modals - Authentication flows
  • Delete confirmations - Prevent accidental deletions
  • Image or media viewers - Display full-size content

Accessibility

The Dialog component follows WAI-ARIA best practices:

  • Uses proper ARIA roles and attributes
  • Supports keyboard navigation (Tab, Shift+Tab, Escape)
  • Traps focus within the dialog when open
  • Returns focus to trigger element when closed
  • Announces dialog content to screen readers
  • Uses DialogTitle as accessible name
  • Uses DialogDescription as accessible description

Styling

The Dialog component uses Tailwind CSS classes and supports customization:

  • Content: max-w-lg width, p-6 padding, rounded corners
  • Overlay: Black backdrop with 80% opacity
  • Animations: Fade in/out with zoom and slide effects
  • Close button: Positioned top-right with hover effects
  • Header: Centered on mobile, left-aligned on desktop
  • Footer: Stacked on mobile, horizontal on desktop

Customize by passing className props to any component:

<DialogContent className="max-w-2xl">
  {/* Wider dialog */}
</DialogContent>

On this page