Feedback
AlertDialog
A confirmation dialog that demands an explicit answer, with role alertdialog and async confirm handling.
<script>
import { AlertDialog } from "@codeatlasdev/ui";
let open = $state(false);
</script>
<AlertDialog
bind:open
title="Delete item?"
description="This action cannot be undone."
confirmLabel="Delete"
destructive
onconfirm={() => api.remove(id)}
/>
Unlike Dialog, there is no close button and a click outside does not dismiss it, and initial focus lands on the dialog itself instead of the first control. Escape and Cancel close it and fire oncancel. Both are ignored while a request is pending.
#081Basic and destructive
Confirm and cancel, with the destructive variant for irreversible actions.
Reference #081 · Pick in the gallery
Code
<script lang="ts">
import { AlertDialog, Button } from '@codeatlasdev/ui';
import { Trash2, LogOut } from '@lucide/svelte';
let signOutOpen = $state(false);
let deleteOpen = $state(false);
let log = $state<string[]>([]);
const push = (m: string) => (log = [m, ...log].slice(0, 4));
</script>
<Button variant="outlined" onclick={() => (signOutOpen = true)}>
{#snippet leading()}<LogOut size={14} />{/snippet}
Sign out
</Button>
<Button variant="destructive" onclick={() => (deleteOpen = true)}>
{#snippet leading()}<Trash2 size={14} />{/snippet}
Delete project
</Button>
<AlertDialog
bind:open={signOutOpen}
title="Sign out?"
description="You will need to sign in again to access your workspace."
confirmLabel="Sign out"
onconfirm={() => push('Signed out')}
oncancel={() => push('Sign out cancelled')}
/>
<AlertDialog
bind:open={deleteOpen}
title="Delete this project?"
description="This action cannot be undone. All data will be permanently removed."
confirmLabel="Delete"
destructive
onconfirm={() => push('Project deleted')}
/>
{#if log.length}
<ul class="log" aria-live="polite">
{#each log as entry, i (i + entry)}<li>{entry}</li>{/each}
</ul>
{/if}
<style>
.log {
flex-basis: 100%;
list-style: none;
margin: 0;
padding: 0;
display: grid;
gap: 4px;
font-size: 13px;
color: var(--ca-text-secondary);
}
</style>
#080Async onconfirm
While the promise is pending the confirm button shows a spinner, Cancel is disabled and Escape is ignored. The dialog closes when it resolves and stays open if it throws.
Reference #080 · Pick in the gallery
Code
<script lang="ts">
import { AlertDialog, Button } from '@codeatlasdev/ui';
let open = $state(false);
let done = $state(false);
const wait = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
async function removeItem() {
await wait(1500);
done = true;
}
</script>
<Button variant="destructive" onclick={() => ((done = false), (open = true))}>Remove item (1.5s)</Button>
<AlertDialog
bind:open
title="Remove item?"
description="The request takes 1.5 seconds."
confirmLabel="Remove"
destructive
onconfirm={removeItem}
/>
{#if done}<span class="note" aria-live="polite">Item removed (async onconfirm resolved).</span>{/if}
<style>
.note { font-size: 13px; color: var(--ca-text-secondary); }
</style>
#082Controlled pending
Pass pending when the loading state lives outside, for example a mutation from your query client.
Reference #082 · Pick in the gallery
Code
<script lang="ts">
import { AlertDialog, Button } from '@codeatlasdev/ui';
let open = $state(false);
let pending = $state(false);
async function publish() {
pending = true;
await new Promise<void>((r) => setTimeout(r, 1500));
pending = false;
open = false;
}
</script>
<Button variant="outlined" onclick={() => (open = true)}>Open controlled</Button>
<AlertDialog bind:open title="Publish changes?" confirmLabel="Publish" {pending} onconfirm={publish} />
#462Type to confirm
children renders a field under the description, confirmDisabled keeps Confirm off until the key matches, description takes a snippet for rich text, and confirmProps tags the button for tests.
Reference #462 · Pick in the gallery
Code
<script lang="ts">
import { AlertDialog, Button, TextField } from '@codeatlasdev/ui';
import { Trash2 } from '@lucide/svelte';
const key = 'PRJ-42';
let open = $state(false);
let typed = $state('');
let deleted = $state(false);
</script>
<Button variant="destructive" onclick={() => { typed = ''; open = true; }}>
{#snippet leading()}<Trash2 size={14} />{/snippet}
Delete {key}
</Button>
{#if deleted}<span class="out" aria-live="polite">{key} deleted.</span>{/if}
<AlertDialog
bind:open
title="Delete {key}?"
confirmLabel="Delete"
cancelVariant="outlined"
destructive
confirmDisabled={typed !== key}
confirmProps={{ 'data-testid': 'confirm-delete' }}
onconfirm={() => (deleted = true)}
>
{#snippet description()}This removes <strong>3 linked records</strong> too and cannot be undone.{/snippet}
<TextField label="Type {key} to confirm" bind:value={typed} />
</AlertDialog>
<style>
.out { font-size: var(--ca-font-size-body2); color: var(--ca-text-secondary); }
</style>
Props
| Prop | Type | Default | Description |
|---|
open | boolean | false | Bindable open state. |
title | string | – | Required. Dialog title and accessible name. |
description | string | Snippet | – | Supporting text below the title. Pass a snippet for rich text; it still describes the dialog. |
children | Snippet | – | Body between the description and the buttons: a confirmation field or a choice. |
confirmLabel | string | 'Confirm' (localized) | Label of the confirm button. Defaults to the active locale's string. |
cancelLabel | string | 'Cancel' (localized) | Label of the cancel button. Defaults to the active locale's string. |
cancelVariant | 'ghost' | 'outlined' | 'glass' | 'filled' | 'ghost' | Variant of the cancel button. |
confirmDisabled | boolean | false | Keeps Confirm disabled, for type-to-confirm. Escape and Cancel still close the dialog. |
confirmProps | { id, class, size, aria-label, aria-describedby, data-* } | – | Attributes for the confirm button. Variant, loading, label and click stay owned by the dialog. |
cancelProps | { id, class, size, aria-label, aria-describedby, data-* } | – | Attributes for the cancel button. |
destructive | boolean | false | Confirm button uses the destructive variant. |
pending | boolean | false | Controls the loading state externally. Without it, pending is automatic while onconfirm is awaited. |
onconfirm | () => void | Promise<void> | – | Required. Closes the dialog when it resolves; if it throws, the dialog stays open and the error propagates. |
oncancel | () => void | – | Fires on Cancel or Escape. Never fires while pending. |
class | string | '' | Extra classes on the panel. |