<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.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional CSS classes merged via `cn()`. |
| children | ReactNode | - | 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. |
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.
Dialog.Trigger
A button that opens the dialog when clicked.
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.
Dialog.Title
A heading that labels the dialog for accessibility.
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.
Dialog.Description
A paragraph providing additional context about the dialog.
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.
Dialog.Close
A button that closes the dialog when clicked.
| Prop | Type | Default |
|---|
No component-specific props. Accepts standard HTML attributes.