<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Dialog from "kumo-svelte/components/dialog";
import XIcon from "phosphor-svelte/lib/XIcon";
</script>
<Dialog.Root>
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props}>Delete</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<div class="mb-4 flex items-start justify-between gap-4">
<Dialog.Title class="text-2xl font-semibold">Modal Title</Dialog.Title>
<Dialog.Close aria-label="Close">
{#snippet child({ props })}
<Button {...props} variant="secondary" shape="square" icon={XIcon} aria-label="Close" />
{/snippet}
</Dialog.Close>
</div>
<Dialog.Description class="text-kumo-subtle">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.
</Dialog.Description>
<div class="mt-8 flex justify-end gap-2">
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="secondary">Cancel</Button>
{/snippet}
</Dialog.Close>
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="destructive">Delete</Button>
{/snippet}
</Dialog.Close>
</div>
</Dialog.Content>
</Dialog.Root>
Import
import * as Dialog from "kumo-svelte/components/dialog"; Usage
<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Dialog from "kumo-svelte/components/dialog";
</script>
<Dialog.Root>
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props}>Open</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<Dialog.Title>Dialog Title</Dialog.Title>
<Dialog.Description>Dialog content goes here.</Dialog.Description>
<div class="mt-4 flex justify-end gap-2">
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="secondary">Cancel</Button>
{/snippet}
</Dialog.Close>
</div>
</Dialog.Content>
</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" | General-purpose modals, forms, content display | Dismissible by default |
role="alertdialog" | Destructive actions, confirmations, critical warnings | Requires explicit user acknowledgment |
Examples
Basic Dialog
<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Dialog from "kumo-svelte/components/dialog";
import XIcon from "phosphor-svelte/lib/XIcon";
</script>
<Dialog.Root>
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props}>Click me</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<div class="mb-4 flex items-start justify-between gap-4">
<Dialog.Title class="text-2xl font-semibold">Modal Title</Dialog.Title>
<Dialog.Close aria-label="Close">
{#snippet child({ props })}
<Button {...props} variant="secondary" shape="square" icon={XIcon} aria-label="Close" />
{/snippet}
</Dialog.Close>
</div>
<Dialog.Description class="text-kumo-subtle">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.
</Dialog.Description>
</Dialog.Content>
</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".
<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Dialog from "kumo-svelte/components/dialog";
import WarningIcon from "phosphor-svelte/lib/WarningIcon";
</script>
<Dialog.Root role="alertdialog">
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props} variant="destructive">Delete Account</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<div class="mb-4 flex items-center gap-3">
<div class="flex h-10 w-10 items-center justify-center rounded-full bg-kumo-danger/20">
<WarningIcon size={20} weight="fill" class="text-kumo-danger" />
</div>
<Dialog.Title class="text-xl font-semibold">Delete Account?</Dialog.Title>
</div>
<Dialog.Description class="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 class="mt-8 flex justify-end gap-2">
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="secondary">Cancel</Button>
{/snippet}
</Dialog.Close>
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="destructive">Delete Account</Button>
{/snippet}
</Dialog.Close>
</div>
</Dialog.Content>
</Dialog.Root>
Confirmation Dialog (with disablePointerDismissal)
For confirmation dialogs that should not be dismissed by clicking outside, use disablePointerDismissal on Dialog.Root.
<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Dialog from "kumo-svelte/components/dialog";
import WarningIcon from "phosphor-svelte/lib/WarningIcon";
</script>
<Dialog.Root disablePointerDismissal>
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props} variant="destructive">Delete Project</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<div class="mb-4 flex items-center gap-3">
<div class="flex h-10 w-10 items-center justify-center rounded-full bg-kumo-danger/20">
<WarningIcon size={20} class="text-kumo-danger" />
</div>
<Dialog.Title class="text-xl font-semibold">Delete Project?</Dialog.Title>
</div>
<Dialog.Description class="text-kumo-subtle">
This action cannot be undone. This will permanently delete the project and all associated data.
</Dialog.Description>
<div class="mt-8 flex justify-end gap-2">
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="secondary">Cancel</Button>
{/snippet}
</Dialog.Close>
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="destructive">Delete</Button>
{/snippet}
</Dialog.Close>
</div>
</Dialog.Content>
</Dialog.Root>
With Actions
<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Dialog from "kumo-svelte/components/dialog";
import XIcon from "phosphor-svelte/lib/XIcon";
</script>
<Dialog.Root>
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props}>Delete</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<div class="mb-4 flex items-start justify-between gap-4">
<Dialog.Title class="text-2xl font-semibold">Modal Title</Dialog.Title>
<Dialog.Close aria-label="Close">
{#snippet child({ props })}
<Button {...props} variant="secondary" shape="square" icon={XIcon} aria-label="Close" />
{/snippet}
</Dialog.Close>
</div>
<Dialog.Description class="text-kumo-subtle">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.
</Dialog.Description>
<div class="mt-8 flex justify-end gap-2">
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="secondary">Cancel</Button>
{/snippet}
</Dialog.Close>
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="destructive">Delete</Button>
{/snippet}
</Dialog.Close>
</div>
</Dialog.Content>
</Dialog.Root>
With Select
Dialog containing a Select dropdown.
<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Dialog from "kumo-svelte/components/dialog";
import * as Select from "kumo-svelte/components/select";
import XIcon from "phosphor-svelte/lib/XIcon";
const regions = [
{ value: "us-east", label: "US East" },
{ value: "us-west", label: "US West" },
{ value: "eu-west", label: "EU West" },
{ value: "ap-south", label: "AP South" },
];
let region = $state("");
</script>
<Dialog.Root>
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props}>Open Form</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<div class="mb-4 flex items-start justify-between gap-4">
<Dialog.Title class="text-2xl font-semibold">Create Resource</Dialog.Title>
<Dialog.Close aria-label="Close">
{#snippet child({ props })}
<Button {...props} variant="secondary" shape="square" icon={XIcon} aria-label="Close" />
{/snippet}
</Dialog.Close>
</div>
<Dialog.Description class="mb-4 text-kumo-subtle">Select a region for your new resource.</Dialog.Description>
<Select.Root
items={regions}
value={region}
onValueChange={(value) => {
region = value as string;
}}
placeholder="Select region..."
class="w-full"
/>
<div class="mt-8 flex justify-end gap-2">
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="secondary">Cancel</Button>
{/snippet}
</Dialog.Close>
<Button variant="primary">Create</Button>
</div>
</Dialog.Content>
</Dialog.Root>
With Combobox
Dialog containing a Combobox for searchable selection.
<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Combobox from "kumo-svelte/components/combobox";
import * as Dialog from "kumo-svelte/components/dialog";
import XIcon from "phosphor-svelte/lib/XIcon";
const regions = [
{ value: "us-east", label: "US East" },
{ value: "us-west", label: "US West" },
{ value: "eu-west", label: "EU West" },
{ value: "ap-south", label: "AP South" },
];
let region = $state("");
</script>
<Dialog.Root>
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props}>Open Form</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<div class="mb-4 flex items-start justify-between gap-4">
<Dialog.Title class="text-2xl font-semibold">Create Resource</Dialog.Title>
<Dialog.Close aria-label="Close">
{#snippet child({ props })}
<Button {...props} variant="secondary" shape="square" icon={XIcon} aria-label="Close" />
{/snippet}
</Dialog.Close>
</div>
<Dialog.Description class="mb-4 text-kumo-subtle">
Search and select a region for your new resource.
</Dialog.Description>
<Combobox.Root bind:value={region}>
<Combobox.TriggerInput class="w-full" placeholder="Search regions..." />
<Combobox.Content>
<Combobox.Empty>No regions found</Combobox.Empty>
<Combobox.List>
{#each regions as item (item.value)}
<Combobox.Item value={item.value}>{item.label}</Combobox.Item>
{/each}
</Combobox.List>
</Combobox.Content>
</Combobox.Root>
<div class="mt-8 flex justify-end gap-2">
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="secondary">Cancel</Button>
{/snippet}
</Dialog.Close>
<Button variant="primary">Create</Button>
</div>
</Dialog.Content>
</Dialog.Root>
With Dropdown
Dialog containing a Dropdown menu.
<script lang="ts">
import { Button } from "kumo-svelte/components/button";
import * as Dialog from "kumo-svelte/components/dialog";
import * as DropdownMenu from "kumo-svelte/components/dropdown";
import XIcon from "phosphor-svelte/lib/XIcon";
</script>
<Dialog.Root>
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props}>Open Form</Button>
{/snippet}
</Dialog.Trigger>
<Dialog.Content class="p-8">
<div class="mb-4 flex items-start justify-between gap-4">
<Dialog.Title class="text-2xl font-semibold">Resource Actions</Dialog.Title>
<Dialog.Close aria-label="Close">
{#snippet child({ props })}
<Button {...props} variant="secondary" shape="square" icon={XIcon} aria-label="Close" />
{/snippet}
</Dialog.Close>
</div>
<Dialog.Description class="mb-4 text-kumo-subtle">Choose an action for the selected resource.</Dialog.Description>
<DropdownMenu.Root>
<DropdownMenu.Trigger>
{#snippet child({ props })}
<Button {...props}>Actions</Button>
{/snippet}
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item>Edit</DropdownMenu.Item>
<DropdownMenu.Item>Duplicate</DropdownMenu.Item>
<DropdownMenu.Separator />
<DropdownMenu.Item variant="danger">Delete</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Root>
<div class="mt-8 flex justify-end">
<Dialog.Close>
{#snippet child({ props })}
<Button {...props} variant="secondary">Close</Button>
{/snippet}
</Dialog.Close>
</div>
</Dialog.Content>
</Dialog.Root>
API Reference
Dialog.Close
No component-specific props. This component accepts child content or standard forwarded attributes.
Dialog.Content
| Prop | Type | Default |
|---|---|---|
| children* | Snippet | — |
| class | string | — |
| container | PortalProps["to"] | — |
| size | KumoDialogSize | KUMO_DIALOG_DEFAULT_VARIANTS.size |
| style | string | — |
| id | string | — |
Dialog.Description
| Prop | Type | Default |
|---|---|---|
| children* | Snippet | — |
| class | string | — |
| id | string | — |
Dialog.Footer
| Prop | Type | Default |
|---|---|---|
| children | Snippet | — |
Dialog.Header
| Prop | Type | Default |
|---|---|---|
| children | Snippet | — |
Dialog.Overlay
No component-specific props. This component accepts child content or standard forwarded attributes.
Dialog.Portal
| Prop | Type | Default |
|---|---|---|
| children | Snippet | — |
| to | PortalProps["to"] | — |
Dialog.Root
| Prop | Type | Default |
|---|---|---|
| children* | Snippet | — |
| role | KumoDialogRole | KUMO_DIALOG_DEFAULT_VARIANTS.role |
| disablePointerDismissal | boolean | false |
| open | boolean | false |
| onOpenChange | (open: boolean) => void | — |
Dialog.Title
| Prop | Type | Default |
|---|---|---|
| children* | Snippet | — |
| class | string | — |
| id | string | — |
| level | 1 | 2 | 3 | 4 | 5 | 6 | 2 |
Dialog.Trigger
No component-specific props. This component accepts child content or standard forwarded attributes.