Skip to content

Alert Stack Undo Delete

Deleting a message hides its row and queues an alert instead of removing it right away. The Undo action restores the row and calls the dismiss function returned by create(). The itemschange event reports each alert as it starts leaving, and a row that is still hidden at that point is deleted for good.

  • Ava Chen Quarterly report draft
  • Noah Patel Standup notes for Tuesday
  • Mia Torres Design review follow-up
  • Liam Novak Invoice #2081 attached

Code

The following example assumes that you have imported the component and set up the theme.

Undo Delete
<div class="inbox">
30 collapsed lines
<ul>
<li id="mail-1">
<div class="text">
<strong>Ava Chen</strong>
<span class="subject">Quarterly report draft</span>
</div>
<button type="button">Delete</button>
</li>
<li id="mail-2">
<div class="text">
<strong>Noah Patel</strong>
<span class="subject">Standup notes for Tuesday</span>
</div>
<button type="button">Delete</button>
</li>
<li id="mail-3">
<div class="text">
<strong>Mia Torres</strong>
<span class="subject">Design review follow-up</span>
</div>
<button type="button">Delete</button>
</li>
<li id="mail-4">
<div class="text">
<strong>Liam Novak</strong>
<span class="subject">Invoice #2081 attached</span>
</div>
<button type="button">Delete</button>
</li>
</ul>
</div>
<sv-alert-stack id="inbox-stack" swipe-dismiss></sv-alert-stack>
<script type="application/x-typescript" module>
38 collapsed lines
const stack = document.querySelector<AlertStack>("#inbox-stack")!;
document.querySelector(".inbox ul")?.addEventListener("click", event => {
const target = event.target as HTMLElement | null;
if (!target) return;
const button = target.closest("button");
if (!button) return;
const row = button.closest("li");
if (!row) return;
const rowContent = row.querySelector(".subject")?.textContent ?? "";
row.hidden = true;
const dismiss = stack.create({
id: `undo-${row.id}`,
severity: "info",
title: "Message deleted",
description: `"${rowContent}" will be removed permanently.`,
duration: 5000,
actionButton: {
label: "Undo",
action: () => {
row.hidden = false;
dismiss();
},
},
});
});
stack.addEventListener("itemschange", event => {
const row = document.getElementById(event.detail.item.id.replace("undo-", ""));
if (event.detail.change === "removed" && row?.hidden) {
row.remove();
}
});
</script>
<style>
57 collapsed lines
.inbox {
max-inline-size: 28rem;
margin-inline: auto;
ul {
display: grid;
padding: 0.25em;
margin: 0;
list-style: none;
background-color: var(--sv-gray-7);
border: 1px solid var(--sv-gray-5);
border-radius: var(--sv-bdr-rad-lg);
}
ul:not(:has(li))::after {
display: block;
padding: 1em;
color: var(--sv-gray-3);
text-align: center;
content: "Inbox zero. Nicely done.";
}
li {
display: flex;
gap: 1em;
align-items: center;
padding: 0.75em 1em;
&[hidden] {
display: none;
}
&:not(:last-child) {
border-block-end: 1px solid var(--sv-gray-6);
}
.text {
display: grid;
flex: 1;
gap: 0.15em;
.subject {
color: var(--sv-gray-3);
}
}
button {
padding: 0.4em 0.8em;
font: inherit;
color: var(--sv-error);
cursor: pointer;
background-color: transparent;
border: 1px solid var(--sv-gray-5);
border-radius: var(--sv-bdr-rad-md);
}
}
}
</style>