Destructive confirm button
Category: Buttons · Tags: delete, confirm, destructive, inline, danger
Q3 launch plan
Delete Q3 launch plan? This can't be undone.
How to use it
Use for a destructive action on one item in a list or settings page where a full modal would be heavy, such as deleting a single project. Name the thing being deleted in the question and on the confirm button, and offer undo or a trash folder where you can. For deletes that cascade widely or need typed confirmation, use a modal dialog instead. Replace the demo handler with your real delete request and change the ids that link the group to its question.
Accessibility
Everything is native <button> elements. Pressing "Delete project" hides it and reveals a role="group" whose question ("Delete Q3 launch plan? This can't be undone.") labels the "Confirm delete" and "Cancel" buttons, and focus moves to Cancel so a second accidental Enter does nothing harmful. Cancel or Escape restores the Delete button and puts focus back on it; confirming replaces the controls with a message that receives focus (tabindex="-1") and is also a role="status" announcement. Every button shows a 2px focus outline. Text is #b91c1c on #ffffff (6.47:1) for Delete, #ffffff on #b91c1c (6.47:1) and on the #991b1b hover (8.31:1) for Confirm, and #0f172a on #ffffff (17.85:1) and on the #e2e8f0 hover (14.48:1) elsewhere.
Source (copy-ready)
<div class="dcl-delconfirm">
<p class="dcl-delconfirm__name">Q3 launch plan</p>
<div class="dcl-delconfirm__controls">
<button type="button" class="dcl-delconfirm__delete">Delete project</button>
<div class="dcl-delconfirm__ask" role="group" aria-labelledby="dcl-delconfirm-question" hidden>
<p class="dcl-delconfirm__question" id="dcl-delconfirm-question">Delete Q3 launch plan? This can't be undone.</p>
<button type="button" class="dcl-delconfirm__confirm">Confirm delete</button>
<button type="button" class="dcl-delconfirm__cancel">Cancel</button>
</div>
</div>
<p class="dcl-delconfirm__done" role="status" tabindex="-1"></p>
</div>
<style>
.dcl-delconfirm { max-width: 26rem; padding: 1rem; border: 1px solid #cbd5e1; border-radius: 0.75rem; font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-delconfirm__name { margin: 0 0 0.75rem; font-weight: 600; color: #0f172a; background-color: #ffffff; }
.dcl-delconfirm__controls { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.dcl-delconfirm__controls[hidden] { display: none; }
.dcl-delconfirm__ask { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.dcl-delconfirm__ask[hidden] { display: none; }
.dcl-delconfirm__question { flex: 1 1 100%; margin: 0; color: #0f172a; background-color: #ffffff; }
.dcl-delconfirm__delete, .dcl-delconfirm__confirm, .dcl-delconfirm__cancel { min-height: 2.75rem; padding: 0 1rem; border-radius: 0.5rem; cursor: pointer; font: inherit; font-weight: 600; }
.dcl-delconfirm__delete[hidden] { display: none; }
.dcl-delconfirm__delete { border: 1px solid #b91c1c; color: #b91c1c; background-color: #ffffff; }
.dcl-delconfirm__delete:hover { color: #b91c1c; background-color: #fef2f2; }
.dcl-delconfirm__confirm { border: 1px solid #b91c1c; color: #ffffff; background-color: #b91c1c; }
.dcl-delconfirm__confirm:hover { color: #ffffff; background-color: #991b1b; }
.dcl-delconfirm__cancel { border: 1px solid #64748b; color: #0f172a; background-color: #ffffff; }
.dcl-delconfirm__cancel:hover { color: #0f172a; background-color: #e2e8f0; }
.dcl-delconfirm__delete:focus-visible, .dcl-delconfirm__confirm:focus-visible, .dcl-delconfirm__cancel:focus-visible { outline: 2px solid #0f172a; outline-offset: 2px; }
.dcl-delconfirm__done { margin: 0; color: #0f172a; background-color: #ffffff; }
.dcl-delconfirm__done:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 2px; }
</style>
<script>
(function () {
document.querySelectorAll(".dcl-delconfirm").forEach(function (root) {
if (root.dataset.dclBound) { return; }
root.dataset.dclBound = "true";
var controls = root.querySelector(".dcl-delconfirm__controls");
var del = root.querySelector(".dcl-delconfirm__delete");
var ask = root.querySelector(".dcl-delconfirm__ask");
var confirm = root.querySelector(".dcl-delconfirm__confirm");
var cancel = root.querySelector(".dcl-delconfirm__cancel");
var done = root.querySelector(".dcl-delconfirm__done");
if (!del || !ask) { return; }
function reset() {
ask.hidden = true;
del.hidden = false;
del.focus();
}
del.addEventListener("click", function () {
del.hidden = true;
ask.hidden = false;
if (cancel) { cancel.focus(); }
});
if (cancel) { cancel.addEventListener("click", reset); }
ask.addEventListener("keydown", function (event) {
if (event.key === "Escape") { event.preventDefault(); reset(); }
});
if (confirm) {
confirm.addEventListener("click", function () {
if (controls) { controls.hidden = true; }
if (done) {
done.textContent = "Project deleted.";
done.focus();
}
});
}
});
})();
</script>
Was this useful? Send feedback.