Live demo: bulk-actions-demo.html (BEFORE/AFTER)
Common failure modes
- Hidden scope: users can’t tell whether an action applies to 1 item or 30.
- Focus theft: after an action, focus jumps to a banner/toast and the user loses their place.
- No tri-state “Select all”: when some items are selected, the control doesn’t show a mixed state.
- Live-region spam: announcing every tiny change interrupts speech.
- Accidental destruction: destructive actions lack a confirm/undo path.
Minimum viable pattern
- Use real checkboxes for selection. Don’t rely on a highlight color alone.
- Keep the bulk toolbar stable (don’t appear/disappear in a way that moves focus).
- Show a persistent selection summary (e.g., “3 selected”).
- Enable bulk action buttons only when selection is non-zero (or explain why disabled).
- Support tri-state “Select all” using
checkbox.indeterminatefor the mixed state. - Announce selection counts and outcomes with
role="status"(polite). Consider a small debounce. - Don’t move focus on completion. If you show a banner, let it be discoverable (not forced).
Tri-state “Select all” checklist
- 0 selected: unchecked + not indeterminate.
- All selected: checked + not indeterminate.
- Some selected: indeterminate = true; checked = false.
Tip: don’t announce “mixed” repeatedly; announce the count.
Destructive actions: prefer undo when possible
If you can, make “Delete” a two-step flow (confirm) or provide an undo toast. If you do show an undo, keep focus stable and announce results politely.