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

Installation

Barrel

import { Dialog } from "@cloudflare/kumo";

Granular

import { Dialog } from "@cloudflare/kumo/components/dialog";

Usage

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>
  );
}

Dialog vs Alert Dialog

The Dialog component supports two ARIA roles to properly convey semantic meaning to assistive technologies:

Role Use Case Behavior
role="dialog" (default) General-purpose modals, forms, content display Dismissible by default
role="alertdialog" Destructive actions, confirmations, critical warnings Requires explicit user acknowledgment
// 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>

Examples

Basic Dialog

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

Alert Dialog (role="alertdialog")

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

When to use role="alertdialog":

  • Destructive actions (delete, discard, remove)
  • Confirmation flows requiring explicit user acknowledgment
  • Actions that cannot be undone
  • Critical warnings or errors
<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>

Confirmation Dialog (with disablePointerDismissal)

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.

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

With Actions

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

With Select

Dialog containing a Select dropdown.

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

With Combobox

Dialog containing a Combobox for searchable selection.

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

With Dropdown

Dialog containing a Dropdown menu.

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

API Reference

Dialog

The main dialog container that renders the modal overlay and popup.

PropTypeDefaultDescription
classNamestring-Additional CSS classes merged via `cn()`.
childrenReactNode-Dialog content (typically Title, Description, Close, and action buttons).
size"base" | "sm" | "lg" | "xl""base"Dialog width. - `"sm"` — Small (min 288px) for simple confirmations - `"base"` — Default (min 384px) - `"lg"` — Large (min 512px) for complex content - `"xl"` — Extra large (min 768px) for detailed views

Dialog.Root

Controls the open state of the dialog. Doesn't render its own HTML element.

Prop Type Default Description
role "dialog" | "alertdialog" "dialog" The ARIA role for the dialog. Use "alertdialog" for destructive or confirmation flows.
disablePointerDismissal boolean false When true, prevents the dialog from being dismissed by clicking outside.
PropTypeDefault

No component-specific props. Accepts standard HTML attributes.

Dialog.Trigger

A button that opens the dialog when clicked.

PropTypeDefault

No component-specific props. Accepts standard HTML attributes.

Dialog.Title

A heading that labels the dialog for accessibility.

PropTypeDefault

No component-specific props. Accepts standard HTML attributes.

Dialog.Description

A paragraph providing additional context about the dialog.

PropTypeDefault

No component-specific props. Accepts standard HTML attributes.

Dialog.Close

A button that closes the dialog when clicked.

PropTypeDefault

No component-specific props. Accepts standard HTML attributes.