> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/shadcn-ui/ui/llms.txt
> Use this file to discover all available pages before exploring further.

# Dialog

> A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @base-ui/react
  ```

  ```bash pnpm theme={null}
  pnpm add @base-ui/react
  ```

  ```bash yarn theme={null}
  yarn add @base-ui/react
  ```

  ```bash bun theme={null}
  bun add @base-ui/react
  ```
</CodeGroup>

Or use the CLI:

```bash theme={null}
npx shadcn@latest add dialog
```

## Usage

```tsx theme={null}
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
```

```tsx theme={null}
<Dialog>
  <DialogTrigger>Open</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>
  </DialogContent>
</Dialog>
```

## Component API

### Dialog

The root dialog component built on Radix UI.

**Props:**

* `open` - Control dialog open state
* `onOpenChange` - Callback when open state changes
* `defaultOpen` - Initial open state
* `modal` - Whether dialog is modal (default: `true`)

### DialogTrigger

The element that opens the dialog.

**Props:**

* `asChild` - Compose with child element

### DialogContent

The dialog content container.

**Props:**

* `showCloseButton` - Show close button (default: `true`)
* `onEscapeKeyDown` - Callback when escape is pressed
* `onPointerDownOutside` - Callback when clicking outside

### DialogHeader

Container for title and description.

### DialogTitle

The dialog title (required for accessibility).

### DialogDescription

The dialog description.

### DialogFooter

Container for dialog actions.

**Props:**

* `showCloseButton` - Show close button (default: `false`)

### DialogClose

Closes the dialog.

## Examples

### Custom Close Button

Replace the default close control with your own button:

```tsx theme={null}
import {
  Dialog,
  DialogClose,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"

export function CustomCloseButton() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Open Dialog</Button>
      </DialogTrigger>
      <DialogContent showCloseButton={false}>
        <DialogHeader>
          <DialogTitle>Custom Close Button</DialogTitle>
          <DialogDescription>
            This dialog uses a custom close button in the footer.
          </DialogDescription>
        </DialogHeader>
        <DialogFooter>
          <DialogClose asChild>
            <Button variant="outline">Cancel</Button>
          </DialogClose>
          <Button>Save changes</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
```

### No Close Button

Hide the close button completely:

```tsx theme={null}
<Dialog>
  <DialogTrigger asChild>
    <Button>Open</Button>
  </DialogTrigger>
  <DialogContent showCloseButton={false}>
    <DialogHeader>
      <DialogTitle>No Close Button</DialogTitle>
      <DialogDescription>
        This dialog has no close button.
      </DialogDescription>
    </DialogHeader>
  </DialogContent>
</Dialog>
```

### Scrollable Content

Long content can scroll while the header stays in view:

```tsx theme={null}
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"

export function ScrollableDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Open</Button>
      </DialogTrigger>
      <DialogContent className="max-h-[80vh] overflow-y-auto">
        <DialogHeader>
          <DialogTitle>Terms and Conditions</DialogTitle>
          <DialogDescription>
            Please read and accept our terms and conditions.
          </DialogDescription>
        </DialogHeader>
        <div className="space-y-4">
          {Array.from({ length: 20 }).map((_, i) => (
            <p key={i}>
              This is example content paragraph {i + 1}. The dialog content
              scrolls while the header and footer remain visible.
            </p>
          ))}
        </div>
      </DialogContent>
    </Dialog>
  )
}
```

### Sticky Footer

Keep actions visible while the content scrolls:

```tsx theme={null}
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"

export function StickyFooterDialog() {
  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button>Open</Button>
      </DialogTrigger>
      <DialogContent className="flex max-h-[80vh] flex-col">
        <DialogHeader>
          <DialogTitle>Long Form</DialogTitle>
          <DialogDescription>
            Fill out the form below to continue.
          </DialogDescription>
        </DialogHeader>
        <div className="flex-1 overflow-y-auto">
          {Array.from({ length: 20 }).map((_, i) => (
            <div key={i} className="mb-4">
              <label className="mb-2 block text-sm font-medium">
                Field {i + 1}
              </label>
              <input
                type="text"
                className="w-full rounded border px-3 py-2"
              />
            </div>
          ))}
        </div>
        <DialogFooter className="sticky bottom-0 bg-background pt-4">
          <Button variant="outline">Cancel</Button>
          <Button>Submit</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
```

### Controlled Dialog

Control the dialog open state:

```tsx theme={null}
import * as React from "react"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"

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

  return (
    <Dialog open={open} onOpenChange={setOpen}>
      <DialogTrigger asChild>
        <Button>Open Dialog</Button>
      </DialogTrigger>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>Controlled Dialog</DialogTitle>
          <DialogDescription>
            This dialog's open state is controlled.
          </DialogDescription>
        </DialogHeader>
        <Button onClick={() => setOpen(false)}>Close from inside</Button>
      </DialogContent>
    </Dialog>
  )
}
```

### Form Dialog

Dialog containing a form:

```tsx theme={null}
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from "@/components/ui/dialog"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"

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">
              Name
            </Label>
            <Input id="name" defaultValue="Pedro Duarte" className="col-span-3" />
          </div>
          <div className="grid grid-cols-4 items-center gap-4">
            <Label htmlFor="username" className="text-right">
              Username
            </Label>
            <Input id="username" defaultValue="@peduarte" className="col-span-3" />
          </div>
        </div>
        <DialogFooter>
          <Button type="submit">Save changes</Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  )
}
```

## Accessibility

* Built on Radix UI for full accessibility
* Focus is trapped within the dialog
* Escape key closes the dialog
* Background content is inert
* Screen reader compatible
* ARIA labels and roles

## API Reference

See the [Base UI Dialog](https://base-ui.com/react/components/dialog#api-reference) documentation for complete API details.
