---
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";

<ComponentSection>
  <ComponentExample
    code={`<Dialog.Root>
  <Dialog.Trigger render={(p) => <Button {...p}>Open Dialog</Button>} />
  <Dialog className="p-8">
    <div className="flex items-start justify-between gap-4 mb-4">
      <Dialog.Title className="text-2xl font-semibold">
        Modal Title
      </Dialog.Title>
      <Dialog.Close
        aria-label="Close"
        render={(props) => (
          <Button
            {...props}
            variant="secondary"
            shape="square"
            icon={<X />}
          />
        )}
      />
    </div>
    <Dialog.Description className="text-kumo-subtle">
      Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </Dialog.Description>
    <div className="mt-8 flex justify-end gap-2">
      <Button variant="secondary">Cancel</Button>
      <Dialog.Close
        render={(props) => (
          <Button variant="destructive" {...props}>
            Delete
          </Button>
        )}
      />
    </div>
  </Dialog>
</Dialog.Root>`}
  >
    <DialogWithActionsDemo client:load />
  </ComponentExample>
</ComponentSection>

<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>

<ComponentSection>
  <Heading level={2}>Usage</Heading>
  <CodeBlock code={`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>
  );
}`} lang="tsx" />
</ComponentSection>

<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-line">
    <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-line">
        <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>

  <CodeBlock code={`// General-purpose dialog
<Dialog.Root>
  <Dialog.Trigger render={(p) => <Button {...p}>Edit Profile</Button>} />
  <Dialog>{/* Form content */}</Dialog>
</Dialog.Root>

// Alert dialog for destructive actions

<Dialog.Root role="alertdialog">
  <Dialog.Trigger render={(p) => <Button variant="destructive" {...p}>Delete</Button>} />
  <Dialog>{/* Confirmation content */}</Dialog>
</Dialog.Root>`} lang="tsx" />
</ComponentSection>

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

<Heading level={3}>Basic Dialog</Heading>
<ComponentExample
  code={`<Dialog.Root>
  <Dialog.Trigger render={(p) => <Button {...p}>Click me</Button>} />
  <Dialog className="p-8">
    <div className="flex items-start justify-between gap-4 mb-4">
      <Dialog.Title className="text-2xl font-semibold">
        Modal Title
      </Dialog.Title>
      <Dialog.Close
        aria-label="Close"
        render={(props) => (
          <Button
            {...props}
            variant="secondary"
            shape="square"
            icon={<X />}
          />
        )}
      />
    </div>
    <Dialog.Description className="text-kumo-subtle">
      Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </Dialog.Description>
  </Dialog>
</Dialog.Root>`}
>
  <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 code={`<Dialog.Root role="alertdialog">

  <Dialog.Trigger
    render={(p) => (
      <Button {...p} variant="destructive">Delete Account</Button>
    )}
  />
  <Dialog className="p-8">
    <div className="mb-4 flex items-center gap-3">
      <div className="flex h-10 w-10 items-center justify-center rounded-full bg-kumo-danger/20">
        <Warning size={20} className="text-kumo-danger" weight="fill" />
      </div>
      <Dialog.Title className="text-xl font-semibold">
        Delete Account?
      </Dialog.Title>
    </div>
    <Dialog.Description className="text-kumo-subtle">
      This action cannot be undone. All your data will be permanently
      removed from our servers. Are you sure you want to proceed?
    </Dialog.Description>
    <div className="mt-8 flex justify-end gap-2">
      <Dialog.Close
        render={(props) => (
          <Button variant="secondary" {...props}>Cancel</Button>
        )}
      />
      <Dialog.Close
        render={(props) => (
          <Button variant="destructive" {...props}>Delete Account</Button>
        )}
      />
    </div>
  </Dialog>
</Dialog.Root>`}>
    <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 code={`<Dialog.Root disablePointerDismissal>

  <Dialog.Trigger
    render={(p) => (
      <Button {...p} variant="destructive">Delete Project</Button>
    )}
  />
  <Dialog className="p-8">
    <div className="mb-4 flex items-center gap-3">
      <div className="flex h-10 w-10 items-center justify-center rounded-full bg-kumo-danger/20">
        <Warning size={20} className="text-kumo-danger" />
      </div>
      <Dialog.Title className="text-xl font-semibold">
        Delete Project?
      </Dialog.Title>
    </div>
    <Dialog.Description className="text-kumo-subtle">
      This action cannot be undone. This will permanently
      delete the project and all associated data.
    </Dialog.Description>
    <div className="mt-8 flex justify-end gap-2">
      <Dialog.Close
        render={(props) => (
          <Button variant="secondary" {...props}>Cancel</Button>
        )}
      />
      <Dialog.Close
        render={(props) => (
          <Button variant="destructive" {...props}>Delete</Button>
        )}
      />
    </div>
  </Dialog>
</Dialog.Root>`}>
    <DialogConfirmationDemo client:load />
  </ComponentExample>

  <Heading level={3}>With Actions</Heading>
  <ComponentExample code={`<Dialog.Root>

  <Dialog.Trigger render={(p) => <Button {...p}>Delete</Button>} />
  <Dialog className="p-8">
    <div className="flex items-start justify-between gap-4 mb-4">
      <Dialog.Title className="text-2xl font-semibold">
        Modal Title
      </Dialog.Title>
      <Dialog.Close
        aria-label="Close"
        render={(props) => (
          <Button
            {...props}
            variant="secondary"
            shape="square"
            icon={<X />}
          />
        )}
      />
    </div>
    <Dialog.Description className="text-kumo-subtle">
      Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    </Dialog.Description>
    <div className="mt-8 flex justify-end gap-2">
      <Button variant="secondary">Cancel</Button>
      <Dialog.Close
        render={(props) => (
          <Button variant="destructive" {...props}>
            Delete
          </Button>
        )}
      />
    </div>
  </Dialog>
</Dialog.Root>`}>
    <DialogWithActionsDemo client:load />
  </ComponentExample>

  <Heading level={3}>With Select</Heading>
  <p>
    Dialog containing a Select dropdown.
  </p>
  <ComponentExample code={`<Dialog.Root>

  <Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
  <Dialog className="p-8">
    <Dialog.Title>Create Resource</Dialog.Title>
    <Dialog.Description>Select a region for your new resource.</Dialog.Description>
    <Select className="w-full">
      <Select.Option value="us-east">US East</Select.Option>
      <Select.Option value="us-west">US West</Select.Option>
      <Select.Option value="eu-west">EU West</Select.Option>
    </Select>
  </Dialog>
</Dialog.Root>`}>
    <DialogWithSelectDemo client:load />
  </ComponentExample>

  <Heading level={3}>With Combobox</Heading>
  <p>
    Dialog containing a Combobox for searchable selection.
  </p>
  <ComponentExample code={`<Dialog.Root>

  <Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
  <Dialog className="p-8">
    <Dialog.Title>Create Resource</Dialog.Title>
    <Dialog.Description>Search and select a region.</Dialog.Description>
    <Combobox value={value} onValueChange={setValue} items={regions}>
      <Combobox.TriggerInput placeholder="Search regions..." />
      <Combobox.Content>
        <Combobox.List>
          {(item) => <Combobox.Item value={item}>{item.label}</Combobox.Item>}
        </Combobox.List>
      </Combobox.Content>
    </Combobox>
  </Dialog>
</Dialog.Root>`}>
    <DialogWithComboboxDemo client:load />
  </ComponentExample>

  <Heading level={3}>With Dropdown</Heading>
  <p>
    Dialog containing a Dropdown menu.
  </p>
  <ComponentExample code={`<Dialog.Root>

  <Dialog.Trigger render={(p) => <Button {...p}>Open Form</Button>} />
  <Dialog className="p-8">
    <Dialog.Title>Resource Actions</Dialog.Title>
    <Dialog.Description>Choose an action.</Dialog.Description>
    <DropdownMenu>
      <DropdownMenu.Trigger render={<Button>Actions</Button>} />
      <DropdownMenu.Content>
        <DropdownMenu.Item>Edit</DropdownMenu.Item>
        <DropdownMenu.Item>Duplicate</DropdownMenu.Item>
        <DropdownMenu.Separator />
        <DropdownMenu.Item variant="danger">Delete</DropdownMenu.Item>
      </DropdownMenu.Content>
    </DropdownMenu>
  </Dialog>
</Dialog.Root>`}>
    <DialogWithDropdownDemo client:load />
  </ComponentExample>
</ComponentSection>

<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-line">
  <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-line">
      <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>
