Recalculation Announcements for Dependent Cells

Permalink to "Recalculation Announcements for Dependent Cells"

In a spreadsheet, changing one number can change a hundred others. A sighted user sees the totals flicker and the chart redraw. A screen reader user hears the edit committed and nothing else — unless they navigate to every dependent cell to check. For financial and planning tools, that silence is risky: the user does not learn that their change pushed the budget over its limit.

This guide shows how to summarise recalculation without flooding the user. It belongs to spreadsheet-style editing grids.

Spec reference

Permalink to "Spec reference"
  • SC 4.1.3 Status Messages (AA) — changes in content that are not given focus must be announced if they are status information. A recalculated total is exactly that.
  • SC 3.3.4 Error Prevention (Legal, Financial, Data) (AA) — for financial submissions, users must be able to review changes; a “what changed” list supports that review.
  • SC 1.4.1 Use of Color (A) — a flash of colour on changed cells is not enough on its own.
  • SC 2.2.2 Pause, Stop, Hide (A) — flashing highlights must stop within five seconds and must not flash more than three times a second (SC 2.3.1).
Ranking which recalculated cells to mention Hierarchy of changed cells after editing B4: the grand total (mentioned by name), two subtotals visible on screen (mentioned), and forty-two off-screen intermediate formulas (counted only). Ranking which recalculated cells to mentionEdit: B4 = 1,500the user's own changeGrand total F20mentioned by name: "Total 18,400, was 18,150"Subtotal F4visible on screen: mentionedSubtotal B20visible on screen: mentioned42 other formulasoff-screen: counted, listed on request
Name what matters, count the rest, list everything on request.

When to use — and when not to

Permalink to "When to use — and when not to"

Announce recalculation when an edit changes cells other than the one edited — totals, derived columns, cross-sheet references. Mention by name only the cells that matter: designated totals, cells with conditional thresholds (“over budget”), and dependents visible in the viewport.

Do not announce every changed cell. “Cell F4 changed to 3,220. Cell F5 changed to …” for forty cells takes minutes to hear and nobody waits for it. Do not announce recalculation at all for edits with no dependents.

The misapplication: putting every recalculated cell into a polite live region as it updates. Screen readers queue some, drop some, and the user hears a random subset in a random order.

Per-cell announcements versus one summary Comparison: announcing every recalculated cell produces a long, unordered stream; one summary names key totals, counts the rest and offers a list. Per-cell announcements versus one summary✗ Every changed cell announced40 messages queued or droppedRandom orderNo sense of scaleCannot be replayed✓ One ranked summaryOne sentence after the editTotals first, then visible cells"and 42 other cells""What changed" command lists them all

Annotated code example

Permalink to "Annotated code example"
// After commit: sheet.recalculate returns [{ ref, label, before, after, isTotal, visible, threshold }]
function announceRecalc(editRef, changes) {
  const others = changes.filter(c => c.ref !== editRef && c.before !== c.after);
  if (!others.length) return;
  const ranked = others.sort((a, b) =>
    (b.threshold - a.threshold) || (b.isTotal - a.isTotal) || (b.visible - a.visible));
  const named = ranked.slice(0, 2).map(c =>
    `${c.label} ${c.after}, was ${c.before}${c.threshold ? `, ${c.threshold}` : ''}`);
  const rest = others.length - named.length;
  const msg = `Recalculated: ${named.join('; ')}` + (rest > 0 ? `; and ${rest} other cells.` : '.');
  // After the commit confirmation, not in the same tick (SC 4.1.3)
  setTimeout(() => { status.textContent = msg; }, 150);
  lastChanges = others;                                       // for "what changed"
  flash(others.filter(c => c.visible));                       // visual cue, under 5 s (SC 2.2.2)
}
/* Changed cells: outline plus a small marker — not colour alone (SC 1.4.1) */
.cell.recalc { outline: 2px dashed #155c38; }
.cell.recalc::after { content: "↻"; margin-inline-start: .25em; }
@media (prefers-reduced-motion: reduce) { .cell.recalc { transition: none; } }

Keyboard & AT behaviour

Permalink to "Keyboard & AT behaviour"
Event Expected announcement AT deviations
Commit B4 “B4 is now 1,500” then “Recalculated: Total 18,400, was 18,150, over budget; Subtotal North 3,220, was 2,970; and 42 other cells.” JAWS may truncate long messages; keep under ~200 characters
Ctrl+Alt+C (“what changed”) Opens a dialog or list of 44 changes —
Navigate to F20 later Cell value read normally —
What the user hears after one edit Timeline after committing a value: at 0 ms the edit confirmation, at 150 ms the recalculation summary, then highlights fade after about three seconds; the full list stays available on demand. What the user hears after one edit0 msEdit confirmed"B4 is now 1,500"150 msSummary"Recalculated: Total 18,400, was 18,150, over budget; …"3 sHighlights fadedashed outlines removedAny timeWhat changedfull list of 44 cells, navigable
Two messages, ordered, and nothing after that unless asked.

Integration context

Permalink to "Integration context"

The edit confirmation that comes first is part of accessible formula bar for spreadsheet grids and entering and exiting cell edit mode. Ordering two messages reliably uses the techniques in announcement queues for competing messages. Numeric changes are easier to understand with direction words, as covered in announcing numeric changes with direction and magnitude.

Gotchas

Permalink to "Gotchas"

Async recalculation. Large sheets recalculate in a worker; the summary must wait for completion, not fire after the first batch. If it takes more than a second, announce “Recalculating…” first.

Undo. Undoing the edit recalculates again. Announce the reverse summary (“Total back to 18,150”) so users know the undo reached the dependents.

Charts bound to the sheet. If a chart updates, mention it once (“Chart updated”) rather than describing the new chart; users can open its table view.

Framework notes

Permalink to "Framework notes"

Calculation engines usually report dependents. HyperFormula (used by Handsontable) returns an array of ExportedChange objects from setCellContents, each with address and new value — capture old values before the call to build “was” text. SheetJS does not recalculate; if you use it with your own engine, record changes in your engine. In React, keep the announcer outside the grid component so a re-render of the sheet does not remount the live region.

// HyperFormula: changes returned by the engine
const before = snapshotFormulaCells(hf);
const changes = hf.setCellContents({ sheet: 0, col: 1, row: 3 }, [[1500]]);
announceRecalc('B4', changes.map(ch => toChange(ch, before)));

Testing checklist

Permalink to "Testing checklist"

Design system notes

Permalink to "Design system notes"

Let sheet authors mark cells as “key results” in the model — totals, KPIs, limits — so the announcer knows what to name without heuristics. Document the summary format in the component guidelines and expose the ranking function so products with special priorities can adjust it.

FAQ

Permalink to "FAQ"
Should recalculation be announced assertively?

No, except when a threshold the user must act on is crossed and the product treats it as an error. Routine recalculation is polite.

How many cells should the summary name?

Two or three at most. Beyond that, count them and offer the full list on request.

What if nothing visible changed but off-screen totals did?

Still announce the key totals. Off-screen is exactly where screen reader users cannot see the effect of their change.

Is a "what changed" dialog a good idea, or should it be a panel?

Either works. A non-modal panel that stays open while editing suits frequent use; a dialog suits occasional review. Make it a list or table with old and new values and a way to jump to each cell.

What about collaborative sheets where other people's edits recalculate cells?

Treat remote edits differently from your own. Do not announce every remote recalculation; offer a quiet indicator and an on-demand summary (“3 cells changed by others since you last checked”), and announce only when a remote change affects the cell the user is editing.

Permalink to "Related"

← Back to Spreadsheet-Style Editing Grids