Audit any chart's accessibility in one command

Functional checks — keyboard, live region, text alternative, contrast — against any chart on any page. No integration, no signup.

npx -p fcharts-js -p playwright fcharts-audit \
  --target https://your.app/dashboard --selector '#chart'

That loads the page in headless Chromium, scopes to the element you pointed at, and runs the functional check battery a markup scanner can't: it presses the keys, reads the accessibility tree, measures the rendered pixels. Report-only — it never gates or blocks anything on a page you don't own — and it works on charts from any library: Chart.js, ECharts, uPlot, Highcharts, a hand-rolled canvas.

What it actually checks

What a real run looks like

Here's the (lightly trimmed) output of a run against the public demo of a widely used dashboard product's time-series panel — a fast, canvas-based chart, exactly the kind teams ship every day:

checks: 5 pass · 17 fail · 13 n/a → report written to ./audit-out

✗ 17 functional check(s) failed on this target:
   ✗ keyboard-announce: no [role="application"] surface to receive keyboard focus
   ✗ live-region-present: no aria-live=polite aria-atomic region
   ✗ text-alternative: no data table with caption + scoped headers
   ✗ canvas-hidden: canvas missing aria-hidden=true
   ✗ keyboard-zoom · escape-dismiss · no-keyboard-trap · focus-visible · …

axe-core: 0 serious/critical violations

Read that last line again. Zero axe violations — and seventeen functional failures. The scanner gave this chart a clean bill of health because a canvas has almost no markup to scan. This is the single most important thing to understand about chart accessibility: scanner-clean and screen-reader-usable are different claims, and only one of them is the one your users (and auditors) care about.

From diagnostic to CI gate

Target mode is a diagnostic. For charts you own, the same engine runs as a regression gate: --fixture mode mounts your configured chart, re-proves every automatable claim against a committed per-criterion baseline, regenerates the VPAT/ACR (EN 301 549, WCAG, and Section 508 editions), and fails the build if any criterion regresses. There's a GitHub Action that wraps both modes, and fcharts-audit --compare old.json new.json diffs two reports so a reviewer sees exactly what changed in conformance between versions.

Try it on your own dashboard first. It takes about a minute, and the failing-check list is the concrete work list your team would otherwise pay an audit to produce. If the list is long and the chart is canvas-based, that's not your fault — it's the default state of every fast charting library. The fix pattern is in how to make canvas charts accessible.