Filings, payments, deletions and exams need undo, error checking or a review step before they become final.
Most typing errors are cheap. Some are not: a court filing sent with the wrong case number, a utility payment for the wrong amount, a permit application deleted for good, an online exam submitted with questions unanswered. WCAG 2.1 success criterion 3.3.4 (Level AA) applies to pages that cause legal commitments or financial transactions, that modify or delete user-controllable data, or that submit test responses. For those pages, at least one of three safeguards must hold:
You need one, not all three. The criterion applies by category, not by severity. Routine saves usually satisfy it through the Checked or Reversible safeguard, so each save of a profile page does not need a confirmation, and logs or analytics are not "user-controllable data".
E-filing, tax and fee payments, benefit applications, school district enrollment and assessments sit squarely in scope. A person who transposes digits, whose assistive technology submits a form early, or who presses Enter in the wrong place has the most to lose. The Title II rule expects these services to meet WCAG 2.1 AA, which includes this criterion. Where a third-party vendor runs the payment step, see vendors and third-party content.
<form action="/efile/submit" method="post">
<!-- every field -->
<button type="submit">Submit filing</button>
</form><!-- Step 3 of 3 -->
<h2>Review your filing</h2>
<dl>
<dt>Case number</dt><dd>2026-CV-04412</dd>
<dt>Document</dt><dd>Motion to continue.pdf</dd>
</dl>
<a href="/efile/edit">Change details</a>
<form action="/efile/submit" method="post">
<input type="checkbox" id="ok" required>
<label for="ok">I have checked the details above.</label>
<button type="submit">Submit filing</button>
</form>delBtn.addEventListener("click", () => {
fetch(`/api/documents/${id}`, { method: "DELETE" });
});<dialog id="confirm-del">
<p>Delete "site-plan.pdf"? This cannot be undone.</p>
<button type="button" id="cancel-del">Keep file</button>
<button type="button" id="really-del">Delete file</button>
</dialog>
<script>
const dlg = document.getElementById("confirm-del");
delBtn.onclick = () => dlg.showModal();
document.getElementById("cancel-del").onclick = () => dlg.close();
document.getElementById("really-del").onclick = () => {
fetch(`/api/documents/${id}`, { method: "DELETE" });
dlg.close();
};
</script><button type="button" id="finish">Finish exam</button>
<script>finish.onclick = () => submitAnswers();</script><button type="button" id="finish">Review and finish</button>
<script>
finish.onclick = () => {
const blank = answers.filter(a => !a.value).length;
reviewText.textContent = blank
? `${blank} questions are unanswered. Go back or submit anyway.`
: "All questions answered. Submit when ready.";
reviewDialog.showModal(); // contains Go back and Submit exam buttons
};
</script>// SwiftUI
Button("Pay $84.20") { Task { await pay(amount) } }// SwiftUI
Button("Review payment") { showReview = true }
.confirmationDialog("Pay $84.20 to Acme Water?", isPresented: $showReview) {
Button("Pay $84.20") { Task { await pay(amount) } }
Button("Change amount", role: .cancel) {}
}// Jetpack Compose
Button(onClick = { submitFiling() }) { Text("Submit filing") }// Jetpack Compose
Button(onClick = { showConfirm = true }) { Text("Review filing") }
if (showConfirm) {
AlertDialog(
onDismissRequest = { showConfirm = false },
title = { Text("Submit filing?") },
text = { Text("Case 2026-CV-04412, Motion to continue.") },
confirmButton = { TextButton(onClick = { submitFiling() }) { Text("Submit") } },
dismissButton = { TextButton(onClick = { showConfirm = false }) { Text("Go back") } }
)
}