Icon-only destructive controls — a bare "X" with no label, no confirmation, and no aria-label — remove items without warning and leave screen reader users with no way to identify what the button does. WCAG 2.2 SC 4.1.2 (Name, Role, Value) and SC 2.5.3 (Label in Name) both require that interactive controls expose an accessible name matching visible text. A user who accidentally taps an unlabeled remove button loses cart items with no recovery path; on mobile, mis-taps are routine. The business impact is measurable: unrecoverable cart losses increase abandonment and support load.
Medium because the damage is self-inflicted data loss rather than a security breach, but the WCAG 2.2 violations expose the site to accessibility litigation risk.
In src/components/CartItem.tsx, replace icon-only remove buttons with labeled controls that include an aria-label, visible text, and a confirmation step:
// src/components/CartItem.tsx
<button
onClick={() => { if (confirm(`Remove ${item.name}?`)) onRemove(item.id) }}
aria-label={`Remove ${item.name}`}
>
Remove
</button>
For quantity inputs, add aria-label={\Quantity for ${item.name}`}` and render a visible "Updated" toast on change so sighted users get feedback without a reload.
ID: ecommerce-cart-ux.cart-management.item-management
Severity: medium
What to look for: Enumerate all destructive actions on the cart page: remove item, clear cart, reduce quantity to zero. For each action, check for: (a) a text label (not icon-only), (b) confirmation dialog or undo option, (c) aria-label for accessibility, (d) visual feedback after action. Count the total destructive controls and how many have at least 2 of these safeguards.
Pass criteria: At least 2 of 4 safeguards are present on every destructive cart control: text label, confirmation/undo, aria-label, and visual feedback. No more than 0 destructive controls should be icon-only without an aria-label. Report: "X destructive controls found, Y have at least 2 safeguards."
Fail criteria: Any destructive control is icon-only (e.g., bare "X") with no aria-label and no confirmation. Updates happen silently with no feedback.
Do NOT pass when: The remove button has an aria-label but no visible text label and no confirmation — screen-reader coverage alone is not sufficient for sighted-user UX.
Skip (N/A) when: Cart page does not display remove or quantity update controls (e.g., single-item cart with no removal option).
Detail on fail: Example: "Cart has 2 destructive controls: unmarked 'X' icon for removal (0 safeguards) and quantity input with no feedback (1 safeguard: aria-label only). 0 of 2 meet the 2-safeguard threshold."
Cross-reference: For ARIA labeling requirements on interactive controls, the Accessibility Fundamentals audit covers form labeling and screen reader compatibility.
Remediation: Add clear labels and confirmation in your cart item component at src/components/CartItem.tsx:
// src/components/CartItem.tsx
function CartItem({ item, onRemove, onUpdateQuantity }) {
return (
<div className="cart-item">
<p>{item.name}</p>
<input
type="number"
value={item.quantity}
onChange={(e) => onUpdateQuantity(item.id, parseInt(e.target.value))}
aria-label={`Quantity for ${item.name}`}
/>
<button
onClick={() => {
if (confirm('Remove this item?')) {
onRemove(item.id)
}
}}
aria-label={`Remove ${item.name}`}
>
Remove
</button>
</div>
)
}