Skip to content

ux.destructive action unconfirmed

github-actions[bot] edited this page Sep 7, 2026 · 3 revisions

ux.destructive-action-unconfirmed

Rule ID: ux.destructive-action-unconfirmed Severity: ERROR Category: ux Target Standards: Nielsen Heuristic #5: Error Prevention (Slips and Lapses), ISO 9241-110 Ergonomics of Human-System Interaction (Suitability for the Task), Material Design & WCAG Defensive Action Guidelines


1. Overview & Core Invariant

Enforces confirmation gating for destructive actions to prevent accidental data loss from slips

Core Invariant:

"Destructive user operations ('delete', 'remove', 'destroy', 'purge', 'revoke') must be gated by a confirmation dialog or 2-step verification."


2. Technical Grounding & Engine Realities

Destructive actions such as deleting user accounts, clearing billing databases, or revoking credentials cause permanent, often irreversible data loss.

Executing these operations on a single click without confirmation exposes users to motor slips, touchscreen taps during scrolling, and mistaken identity clicks. Gating destructive actions behind an explicit confirmation dialog (e.g. '' or 'window.confirm') provides a cognitive pause and protects against catastrophic slips.


3. Vulnerability & Risk Taxonomy

Risk Vector Severity Impact
Irreversible Data Destruction from Motor Slips CRITICAL Accidental single-click actions immediately wipe critical business data or terminate accounts without user consent.
User Anxiety & Hesitation MEDIUM Users fear interacting with danger-styled buttons when no confirmation boundary protects them from permanent loss.

4. Non-Compliant Code Patterns (Bad Examples)

TSX (Destructive button triggering account deletion directly on single click):

<button
  onClick={() => deleteAccount(user.id)}
  className="bg-destructive text-destructive-foreground px-4 py-2 rounded"
>
  Hapus Akun Permanen
</button>

5. Compliant Implementation Patterns (Good Examples)

TSX (Destructive button safely wrapped in AlertDialogTrigger confirmation modal):

<AlertDialogTrigger asChild>
  <button className="bg-destructive text-destructive-foreground px-4 py-2 rounded">
    Hapus Akun Permanen
  </button>
</AlertDialogTrigger>

TSX (Staged deletion flow via local useState and downstream confirmation dialog):

const [confirmIndex, setConfirmIndex] = useState<number | null>(null);

<Button variant="destructive" onClick={() => setConfirmIndex(index)}>
  Hapus
</Button>

<ActionApprovalDialog
  open={confirmIndex !== null}
  onConfirm={() => deleteUser(confirmIndex)}
/>

6. How to Suppress (Ignore Directives)

If this pattern is required for an intentional exception, suppress the diagnostic using the canonical Charites Rule ID:

<!-- charites:ignore ux.destructive-action-unconfirmed intentional exception -->
// charites:ignore ux.destructive-action-unconfirmed intentional exception

7. Configuration Reference (charites.yaml)

rules:
  ux.destructive-action-unconfirmed:
    severity: error # error | warn | info | off

8. Architectural Domain & Verification Reference


Rule Categories

A11y (16 rules)
Browser (12 rules)
Cls (16 rules)
Design (1 rules)
Ergonomy (5 rules)
Inp (16 rules)
Lcp (16 rules)
Mobile (5 rules)
Performance (16 rules)
Pwa (10 rules)
Responsive (18 rules)
Semantic (1 rules)
Theme (32 rules)
Ux (20 rules)

Clone this wiki locally