Overlays & tabs
Dialog for a modal task, ConfirmDialog for a destructive one-liner, Popover for an anchored menu, TabBlock for in-page sections.
Dialog
A composed, context-driven modal — Dialog owns open state, DialogTrigger/DialogBody/DialogFooter read it via context.
<Dialog bind:open>
<DialogTrigger><Button>Open dialog</Button></DialogTrigger>
<DialogBody title="Invite teammate" description="They'll get an email with a join link.">
<DialogFooter>
<DialogCloseButton>Cancel</DialogCloseButton>
<Button onclick={sendInvite}>Send invite</Button>
</DialogFooter>
</DialogBody>
</Dialog>ConfirmDialog
The Dialog + confirm/cancel pattern collapsed into one component — pass a trigger snippet and an onConfirm handler.
<ConfirmDialog title="Delete campaign?" description="This can't be undone." onConfirm={deleteCampaign}>
{#snippet trigger()}
<Button variant="ghost-destructive">Delete campaign</Button>
{/snippet}
</ConfirmDialog>Popover
Anchored under its own parent element (position: relative), escapes ancestor overflow-clip via position: fixed.
<div style="position: relative;">
<button onclick={() => (open = !open)}>Options</button>
<Popover bind:open width={200}>
<button class="item">Rename</button>
<button class="item">Archive</button>
</Popover>
</div>FilterPopover
Compact filter panel with Clear and Apply. The draft only commits on Apply; Esc or an outside click discards it.
Applied: none
<div style="position: relative;">
<button onclick={() => { draft.reset(); open = true; }}>Company</button>
<FilterPopover
bind:open
title="Company"
side="right"
onApply={draft.apply}
onClear={draft.clear}
onCancel={draft.reset}
>
<FilterChipGroup label="Popular" chips={popular} selected={draft.values} onToggle={toggle} />
<FilterOptionList searchable options={companies} bind:selected={draft.values} />
</FilterPopover>
</div>FilterPopover — single select, loading and error
Single-select list, plus the loading and error body states.
<FilterPopover bind:open title="Company" {loading} {error} ...>
<FilterOptionList multiple={false} options={companies} bind:selected />
</FilterPopover>TabBlock
Context-driven tab strip — TabBlock owns the active value, TabButton reads/sets it. Pair with your own conditional to render the panel.
Overview panel — the default, high-level summary.
<TabBlock bind:value={tab}>
<TabButton value="overview">Overview</TabButton>
<TabButton value="activity">Activity</TabButton>
<TabButton value="settings">Settings</TabButton>
</TabBlock>