---
layout: ~/layouts/MdxDocLayout.astro
title: "Dialog"
description: "A window overlaid on either the primary window or another dialog window, rendering the content underneath inert."
sourceFile: "components/dialog"
baseUIComponent: "dialog"
---

import ComponentExample from "~/components/docs/ComponentExample.astro";
import ComponentSection from "~/components/docs/ComponentSection.astro";
import CodeBlock from "~/components/docs/CodeBlock.astro";
import Heading from "~/components/docs/Heading.astro";
import PropsTable from "~/components/docs/PropsTable.astro";
import {
  DialogBasicDemo,
  DialogWithActionsDemo,
  DialogConfirmationDemo,
  DialogAlertDemo,
  DialogWithSelectDemo,
  DialogWithComboboxDemo,
  DialogWithDropdownDemo,
} from "~/components/demos/DialogDemo";

{/* Hero Demo */}

<ComponentSection>
  <ComponentExample demo="DialogWithActionsDemo">
    <DialogWithActionsDemo client:load />
  </ComponentExample>
</ComponentSection>

{/* Installation */}

<ComponentSection>
  <Heading level={2}>Installation</Heading>
  <Heading level={3}>Barrel</Heading>
  <CodeBlock code={`import { Dialog } from "@cloudflare/kumo";`} lang="tsx" />
  <Heading level={3}>Granular</Heading>
  <CodeBlock
    code={`import { Dialog } from "@cloudflare/kumo/components/dialog";`}
    lang="tsx"
  />
</ComponentSection>

{/* Usage */}

<ComponentSection>
  <Heading level={2}>Usage</Heading>

```tsx
import { Dialog, Button } from "@cloudflare/kumo";

export default function Example() {
  return (
    <Dialog.Root>
      <Dialog.Trigger render={(p) => <Button {...p}>Open</Button>} />
      <Dialog>
        <Dialog.Title>Dialog Title</Dialog.Title>
        <Dialog.Description>Dialog content goes here.</Dialog.Description>
        <div className="flex justify-end gap-2 mt-4">
          <Dialog.Close
            render={(p) => (
              <Button variant="secondary" {...p}>
                Cancel
              </Button>
            )}
          />
        </div>
      </Dialog>
    </Dialog.Root>
  );
}
```

</ComponentSection>

{/* Dialog vs Alert Dialog */}

<ComponentSection>
  <Heading level={2}>Dialog vs Alert Dialog</Heading>
  <p>
    The Dialog component supports two ARIA roles to properly convey semantic
    meaning to assistive technologies:
  </p>

  <div class="overflow-hidden rounded-lg border border-kumo-hairline">
    <table class="w-full text-sm">
      <thead class="bg-kumo-elevated">
        <tr>
          <th class="px-4 py-3 text-left font-medium">Role</th>
          <th class="px-4 py-3 text-left font-medium">Use Case</th>
          <th class="px-4 py-3 text-left font-medium">Behavior</th>
        </tr>
      </thead>
      <tbody class="divide-y divide-kumo-hairline">
        <tr>
          <td class="px-4 py-3">
            `role="dialog"`
            <span class="ml-2 text-kumo-subtle">(default)</span>
          </td>
          <td class="px-4 py-3">
            General-purpose modals, forms, content display
          </td>
          <td class="px-4 py-3">Dismissible by default</td>
        </tr>
        <tr>
          <td class="px-4 py-3">`role="alertdialog"`</td>
          <td class="px-4 py-3">
            Destructive actions, confirmations, critical warnings
          </td>
          <td class="px-4 py-3">Requires explicit user acknowledgment</td>
        </tr>
      </tbody>
    </table>
  </div>
</ComponentSection>

{/* Examples */}

<ComponentSection>
  <Heading level={2}>Examples</Heading>

<Heading level={3}>Basic Dialog</Heading>
<ComponentExample demo="DialogBasicDemo">
  <DialogBasicDemo client:load />
</ComponentExample>

<Heading level={3}>
  Alert Dialog (<code class="font-normal">role="alertdialog"</code>)
</Heading>
<p>
  For destructive or confirmation dialogs, use `role="alertdialog"` on
  `Dialog.Root`. This provides proper accessibility semantics by rendering the
  dialog with `role="alertdialog"` instead of `role="dialog"`.
</p>
<div class="mb-4 rounded-lg border border-kumo-info/30 bg-kumo-info/10 p-4 text-sm text-kumo-info">
  <p class="font-medium mb-2">
    When to use{" "}
    <code class="bg-kumo-info/20 px-1 rounded">role="alertdialog"</code>:
  </p>
  <ul class="list-disc list-inside space-y-1 ml-2">
    <li>Destructive actions (delete, discard, remove)</li>
    <li>Confirmation flows requiring explicit user acknowledgment</li>
    <li>Actions that cannot be undone</li>
    <li>Critical warnings or errors</li>
  </ul>
</div>
<ComponentExample demo="DialogAlertDemo">
  <DialogAlertDemo client:load />
</ComponentExample>

<Heading level={3}>
  Confirmation Dialog (with{" "}
  <code class="font-normal">disablePointerDismissal</code>)
</Heading>
<p>
  For confirmation dialogs that should not be dismissed by clicking outside, use
  `disablePointerDismissal` on `Dialog.Root`. This can be combined with
  `role="alertdialog"` for proper accessibility.
</p>
<ComponentExample demo="DialogConfirmationDemo">
  <DialogConfirmationDemo client:load />
</ComponentExample>

<Heading level={3}>With Actions</Heading>
<ComponentExample demo="DialogWithActionsDemo">
  <DialogWithActionsDemo client:load />
</ComponentExample>

<Heading level={3}>With Select</Heading>
<p>Dialog containing a Select dropdown.</p>
<ComponentExample demo="DialogWithSelectDemo">
  <DialogWithSelectDemo client:load />
</ComponentExample>

<Heading level={3}>With Combobox</Heading>
<p>Dialog containing a Combobox for searchable selection.</p>
<ComponentExample demo="DialogWithComboboxDemo">
  <DialogWithComboboxDemo client:load />
</ComponentExample>

  <Heading level={3}>With Dropdown</Heading>
  <p>Dialog containing a Dropdown menu.</p>
  <ComponentExample demo="DialogWithDropdownDemo">
    <DialogWithDropdownDemo client:load />
  </ComponentExample>
</ComponentSection>

{/* API Reference */}

<ComponentSection>
  <Heading level={2}>API Reference</Heading>

<Heading level={3}>Dialog</Heading>
<p>The main dialog container that renders the modal overlay and popup.</p>
<PropsTable component="Dialog" />

<Heading level={3}>Dialog.Root</Heading>
<p>
  Controls the open state of the dialog. Doesn't render its own HTML element.
</p>
<div class="mb-4 overflow-hidden rounded-lg border border-kumo-hairline">
  <table class="w-full text-sm">
    <thead class="bg-kumo-elevated">
      <tr>
        <th class="px-4 py-2 text-left font-medium">Prop</th>
        <th class="px-4 py-2 text-left font-medium">Type</th>
        <th class="px-4 py-2 text-left font-medium">Default</th>
        <th class="px-4 py-2 text-left font-medium">Description</th>
      </tr>
    </thead>
    <tbody class="divide-y divide-kumo-hairline">
      <tr>
        <td class="px-4 py-2 font-mono text-xs">role</td>
        <td class="px-4 py-2 font-mono text-xs">"dialog" | "alertdialog"</td>
        <td class="px-4 py-2 font-mono text-xs">"dialog"</td>
        <td class="px-4 py-2 text-kumo-subtle">
          The ARIA role for the dialog. Use `"alertdialog"` for destructive or
          confirmation flows.
        </td>
      </tr>
      <tr>
        <td class="px-4 py-2 font-mono text-xs">disablePointerDismissal</td>
        <td class="px-4 py-2 font-mono text-xs">boolean</td>
        <td class="px-4 py-2 font-mono text-xs">false</td>
        <td class="px-4 py-2 text-kumo-subtle">
          When true, prevents the dialog from being dismissed by clicking
          outside.
        </td>
      </tr>
    </tbody>
  </table>
</div>
<PropsTable component="Dialog.Root" />

<Heading level={3}>Dialog.Trigger</Heading>
<p>A button that opens the dialog when clicked.</p>
<PropsTable component="Dialog.Trigger" />

<Heading level={3}>Dialog.Title</Heading>
<p>A heading that labels the dialog for accessibility.</p>
<PropsTable component="Dialog.Title" />

<Heading level={3}>Dialog.Description</Heading>
<p>A paragraph providing additional context about the dialog.</p>
<PropsTable component="Dialog.Description" />

  <Heading level={3}>Dialog.Close</Heading>
  <p>A button that closes the dialog when clicked.</p>
  <PropsTable component="Dialog.Close" />
</ComponentSection>
