a11y-ci catches the accessibility issues a pull request adds
Most teams have an accessibility backlog. Fail the build on all of it and somebody turns the check off. a11y-ci only flags what your change adds.
Every team I have worked with has an accessibility backlog. Hundreds of old issues nobody has time for this sprint.
Here is the problem. Add an accessibility check to your build that fails on all of those old issues, and it fails on every pull request. Within a week somebody turns it off. I have watched it happen more than once.
I wanted a check that asks one question: did this change make things worse?
That is a11y-ci. It is free on GitHub at InnerSpark/a11y-ci.
How it works
It loads your app in a real browser, the way a user would see it. Then it does the same for your main branch and compares the two. You only hear about the problems your change added.
Only new problems block you.
It also sorts what it finds by who it hurts. “A blind user cannot submit this form” shows up before “the page title is a little long.”
Two places it catches things
While you write the code. Run a11y-ci lint and it reads your HTML and JSX for the classic mistakes: a clickable <div>, an image with no alt text, a button with no name. It takes about half a second, so you can run it every time you commit.
On the pull request. The GitHub Action checks your preview build against main and leaves a comment with anything new. It starts out as a heads-up only. Once you trust it, you can let it block merges.
- uses: InnerSpark/a11y-ci/[email protected]
with:
base-url: ${{ env.PREVIEW_BASE_URL }}
head-url: ${{ env.PREVIEW_HEAD_URL }}
routes: "/,/checkout,/account"
fail-on: none # set to 'new-serious' to block
Everything runs in your own pipeline. Nothing gets sent anywhere.
Where AI fits in
If you want, plug in your own Claude key. It will suggest a fix for each new issue, and look at things a scanner can’t judge, like alt text that is there but says nothing useful.
The AI only gives advice. It never decides whether your build passes. A check that can block your merge needs to give the same answer every time.
What it misses
I would rather tell you up front.
- It takes one snapshot of the page. Anything that happens later, like an auto-logout or a carousel that moves on its own, it never sees.
- It can’t tell how important a button is. It will flag a new icon button with no label. You still have to decide if that button is “Add to cart” or something minor.
- Look-alikes can slip by. If two unlabeled buttons look the same to it and swap places, it won’t notice.
Automated tools catch part of the picture. Somebody with a keyboard and a screen reader still needs to check the rest.
Try it
npx @a11yci/cli lint src
Want dashboards, full-site crawls, pages behind a login, and VPAT reports? That is AccessSpark.