Dialog
Pick a framework. Both use the same recipe, so the styling matches exactly.
No decision yet.
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | false | Shows the dialog as a modal. In Svelte it is bindable with bind:open. |
| title | string | Heading text, wired to the dialog via aria-labelledby. | |
| description | string | Supporting text under the title, wired via aria-describedby. | |
| size | "sm" | "md" | md | Panel width. |
| onClose | () => void | Called after the dialog closes by any path: Escape, backdrop click, or open turning false. | |
| footer | content | Action row under the body. A snippet in Svelte, a ReactNode in React. |
Also takes className and children. Anything else passes through to the dialog.
import { useState } from "react";
import { Button, Dialog } from "../react/index.js";
export default function DialogDemo() {
const [open, setOpen] = useState(false);
const [outcome, setOutcome] = useState("No decision yet.");
const askToDelete = () => {
setOutcome("No decision yet.");
setOpen(true);
};
return (
<div className="flex flex-col items-start gap-3">
<Button variant="secondary" onClick={askToDelete}>
Delete draft
</Button>
<p className="text-sm text-ink-secondary">{outcome}</p>
<Dialog
open={open}
title="Delete draft?"
description="This removes the draft from your workspace."
size="sm"
onClose={() => {
setOpen(false);
setOutcome((v) =>
v === "No decision yet." ? "Dismissed, draft kept." : v,
);
}}
footer={
<>
<Button variant="secondary" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button
onClick={() => {
setOutcome("Draft deleted.");
setOpen(false);
}}
>
Confirm
</Button>
</>
}
>
<p className="text-sm text-ink-secondary">
The draft "Aurora launch notes" will be gone for good. Published posts
are not affected.
</p>
</Dialog>
</div>
);
}
No decision yet.
| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | false | Shows the dialog as a modal. In Svelte it is bindable with bind:open. |
| title | string | Heading text, wired to the dialog via aria-labelledby. | |
| description | string | Supporting text under the title, wired via aria-describedby. | |
| size | "sm" | "md" | md | Panel width. |
| onclose | () => void | Called after the dialog closes by any path: Escape, backdrop click, or open turning false. | |
| footer | content | Action row under the body. A snippet in Svelte, a ReactNode in React. |
Also takes class and snippet children. Anything else passes through to the dialog.
<script lang="ts">
import { Button, Dialog } from "../svelte/index.js";
let open = $state(false);
let outcome = $state("No decision yet.");
function askToDelete() {
outcome = "No decision yet.";
open = true;
}
</script>
<div class="flex flex-col items-start gap-3">
<Button variant="secondary" onclick={askToDelete}>Delete draft</Button>
<p class="text-sm text-ink-secondary">{outcome}</p>
<Dialog
bind:open
title="Delete draft?"
description="This removes the draft from your workspace."
size="sm"
onclose={() => {
if (outcome === "No decision yet.") outcome = "Dismissed, draft kept.";
}}
>
<p class="text-sm text-ink-secondary">
The draft "Aurora launch notes" will be gone for good. Published posts are
not affected.
</p>
{#snippet footer()}
<Button variant="secondary" onclick={() => (open = false)}>Cancel</Button>
<Button
onclick={() => {
outcome = "Draft deleted.";
open = false;
}}
>
Confirm
</Button>
{/snippet}
</Dialog>
</div>