Open source · Accessibility

Accessible Form Error Checker

Check form error text, associations, focus movement and recovery behavior.

v0.1.0 · Node.js 22+ · MIT

Browse the public repository · View releases

For every field, in every state, it checks that the error the state declares is the message written about that field, that the field actually references it, that the message would show some text and is recorded as present, that a field the state declares no error for carries no error state left over from an earlier one, that the summary links to every field in error and to nothing else, that focus after a failed submission landed somewhere the expectations permit, and that an asynchronous check was recorded both while it ran and after it settled.

This walkthrough uses the tool's public README and checked-in example files. Run the command from a repository checkout with Node.js 22+; inspect the source before using it on your own files.

Run the checked-in example

# a form whose error handling holds up
node bin/accessible-form-error-checker.mjs \
  --snapshot examples/clean/snapshot.json \
  --expectations examples/clean/expectations.json \
  --now 2026-09-18
echo $?   # 0

# the same form with the email error wired to the postcode message, focus left
# on a hint, an unexposed asynchronous wait and a corrected field still in error
node bin/accessible-form-error-checker.mjs \
  --snapshot examples/broken/snapshot.json \
  --expectations examples/broken/expectations.json \
  --now 2026-09-18
echo $?   # 1

Read the result

npm run example runs the first of those and npm run example:broken the second. --now is passed so the verdict does not depend on the day it is run; see The clock.

Where this check stops

Exceeding a limit is an incomplete result naming the limit. It is never a silent truncation and never a pass. Bounds that are not configurable: an id or state name is at most 128 characters, an aria-describedby or aria-labelledby list at most 32 entries, a summary at most 500 links, unreadableRegions at most 200 entries, and the expectations document itself at most 262144 bytes.

Before adapting the command to your own workflow, review the accepted inputs, exit codes and safety boundaries in the README.

Compiled with AI assistance from checked-in public documentation and example scripts. Run the example and review the repository's current documentation before relying on its result.