Dev.to WebDev 🛠 Dev 👁 0 📖 3 min read

Turning an axe-core scan into a defensible ADA Title II evidence binder

This is a real deliverable CivicBinder produces — a filed ADA Title II readiness binder for a small municipality. It's live: point it at a city's web presence, and it audits, gathers evidence, and assembles the whole thi

Turning an axe-core scan into a defensible ADA Title II evidence binder

Sample CivicBinder readiness report: a cover page reading This is a real deliverable CivicBinder produces — a filed ADA Title II readiness binder for a small municipality. It's live: point it at a city's web presence, and it audits, gathers evidence, and assembles the whole thing. Everything below is how it actually works.

The April 2024 DOJ rule gave state and local governments a hard deadline to conform their web content to WCAG 2.1 AA. A small city clerk cannot read a WCAG spec. So the interesting engineering problem isn't "run a scanner" — it's turning scanner output into something that survives a records request.

Watch the CivicBinder — ADA Title II compliance, done for you demo

Automated scans cover maybe a third of WCAG

The first thing you learn: axe-core (and every tool built on it) is honest about only catching ~30–40% of WCAG success criteria. Color contrast, missing alt text, form labels, ARIA misuse — machine-verifiable. But "is this alt text meaningful?" or "does the reading order make sense?" — not.

If you dump raw axe violations into a PDF and call it a binder, you've produced a document that quietly claims full coverage while silently omitting the half a scanner can't see. That's the opposite of defensible. So the core design decision is a three-way split on every success criterion:

for each SC in WCAG_2_1_AA:
    checks = rules_mapping[SC]          # axe rule ids → SC
    if checks and all machine-verifiable:
        status = run_axe(checks)         # PASS / FAIL, with evidence
    elif checks partially cover SC:
        status = "PARTIAL — machine-checked + needs review"
    else:
        status = "MANUAL — human attestation required"

Every SC lands in exactly one bucket, and the binder shows all three. The clerk sees precisely what the tool verified and what a human still has to sign off on. Honesty is the feature.

CivicBinder — ADA Title II compliance site

The mapping table is the actual product

axe emits rule ids like color-contrast and image-alt. WCAG is organized by success criterion — 1.4.3, 1.1.1. The glue is a hand-curated map, because it's many-to-many: one SC can need several axe rules, and one rule can touch several SCs.

"1.1.1": ["image-alt", "input-image-alt", "area-alt", "object-alt"],
"1.4.3": ["color-contrast"],
"4.1.2": ["aria-required-attr", "button-name", "link-name", ...],

Get this table wrong and the whole binder is wrong. It's the part I'd never let a model hallucinate — it's reviewed against the official ACT rules and pinned to an axe version, because rule ids drift between releases.

Evidence needs provenance, not just a boolean

A "PASS" with no proof is worthless in a filing. So for every finding the crawler captures, at scan time:

  • the URL and a content hash of the page,
  • the DOM node and selector that triggered (or cleared) the rule,
  • a screenshot with the element highlighted,
  • an ISO-8601 timestamp.

That bundle is what makes a line in the table a piece of evidence instead of an assertion. When someone asks "prove the city was compliant on this date," the binder answers with a timestamped artifact, not a claim.

The crawl is messier than a SaaS site

Municipal web presence is not one Next.js app. It's a main .gov site, a third-party permit portal, a legacy PDF library, an agenda-management subdomain, and an embedded payment iframe — different owners, different auth. The crawler treats each surface as its own scope with its own coverage report, and PDFs get routed to a separate document-accessibility check entirely (tagged structure, reading order), because axe only speaks HTML.

The lesson that generalizes past ADA: compliance tooling lives or dies on the boring mapping layer and the evidence provenance — not the scanner. The scanner is a commodity; the defensible trail around it is the work.

I built this into a done-for-you product — book a slot and I'll run your city's binder.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.