a11y-commit-validator
v2.1.1
Published
Pre-commit accessibility validator for HTML, JSX, JS and Liquid files. Blocks commits with WCAG violations and provides GitHub Copilot-powered fix suggestions.
Maintainers
Readme
a11y-commit-validator ♿
The accessibility guardian for your Git workflow.
Automatically scans staged HTML, JSX, JS and Liquid files for WCAG violations before every commit — powered by axe-core, eslint-plugin-jsx-a11y, and AI-powered fix suggestions (Groq, GitHub Models, or OpenAI — your choice).
✨ Features
- ♿ WCAG 2.0 / 2.1 / 2.2 Compliance — Full audit via axe-core for HTML files
- ⚛️ React / JSX Support — AST-level analysis with eslint-plugin-jsx-a11y
- 💧 Liquid Template Support — Regex-based rules for Shopify / Liquid files
- 🤖 AI-Powered Suggestions — 3 providers supported (Groq, GitHub Models, OpenAI). Works with whichever you have. Falls back to built-in suggestions if none configured
- 🔧 Auto-Fix Mode — Automatically patches fixable issues and re-stages them
- 🎨 Beautiful Terminal UI — Animated spinners, coloured output, progress bar
- 🛡️ Zero Config — Works out of the box, no
.eslintrcor config files needed - 🔌 Husky / pre-commit ready — Drop-in integration with any Git hook tool
What it does
Every time you run git commit, this tool:
- Detects which
.html,.jsx,.js, and.liquidfiles you've staged - Scans them for WCAG 2.1 / 2.2 accessibility violations using:
- axe-core (deep audit for HTML via jsdom)
- eslint-plugin-jsx-a11y (AST-level JSX/React analysis)
- Regex rules (custom patterns for Liquid + extra JSX checks)
- Explains every issue and suggests a fix (via AI or built-in rules)
- Blocks the commit if issues are found — and optionally auto-fixes them
🚀 Installation
# Install as a dev dependency (recommended)
npm install --save-dev a11y-commit-validator
# Or install globally
npm install -g a11y-commit-validator⚙️ Configuration
Step 1 — Create your .env file
Create a .env file in the root of your project and add one (or more) AI provider keys:
# ── Option A: Groq (RECOMMENDED — completely free, no credit card) ────────────
GROQ_API_KEY=gsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# ── Option B: GitHub Models (requires a GitHub personal access token) ─────────
# GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# ── Option C: OpenAI (requires a paid OpenAI API key) ─────────────────────────
# OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxThat's it — just one line in
.envis all you need.
🤖 AI Providers — How the Cascade Works
The tool tries your configured providers in priority order. The first one that responds successfully is used. If none are available, it falls back to built-in suggestions automatically.
┌─────────────────────────────────────────────────────────────┐
│ AI Provider Cascade (auto-fallback) │
│ │
│ 1️⃣ GITHUB_TOKEN set? ──→ Try GitHub Models (gpt-4o) │
│ │ blocked / error │
│ ▼ │
│ 2️⃣ OPENAI_API_KEY set? ──→ Try OpenAI API │
│ │ error │
│ ▼ │
│ 3️⃣ GROQ_API_KEY set? ──→ Try Groq (LLaMA 3.3 70B) ✅ │
│ │ error │
│ ▼ │
│ 4️⃣ None configured ──→ Built-in rule suggestions │
└─────────────────────────────────────────────────────────────┘Provider Comparison
| Provider | Key name in .env | Cost | Best for |
|---|---|---|---|
| Groq ⭐ | GROQ_API_KEY | Free — console.groq.com | Everyone. No credit card, fast LLaMA 3.3 70B |
| GitHub Models | GITHUB_TOKEN | Free with GitHub account | If your org allows GitHub Models API |
| OpenAI | OPENAI_API_KEY | Paid — platform.openai.com | If you already have an OpenAI subscription |
We recommend Groq — it's completely free, no credit card, and uses LLaMA 3.3 70B which gives excellent WHY + FIX suggestions for accessibility.
Getting a free Groq API key (2 minutes)
- Go to console.groq.com
- Sign in with Google or GitHub — no credit card needed
- Click API Keys → Create API key
- Paste into your
.env:GROQ_API_KEY=gsk_...
Environment Variables Reference
| Variable | Provider | Description |
|---|---|---|
| GROQ_API_KEY | Groq (free) | LLaMA 3.3 70B — sign up at console.groq.com |
| GITHUB_TOKEN | GitHub Models | Personal access token from github.com/settings/tokens |
| OPENAI_API_KEY | OpenAI | API key from platform.openai.com/api-keys |
| A11Y_GROQ_MODEL | Groq only | Override default model (default: llama-3.3-70b-versatile) |
No key at all? The tool still works — built-in rule-based WHY + FIX suggestions are included for every rule.
⚙️ Setup
Option 1 — Husky (recommended)
npm install --save-dev husky
npx husky install
npx husky add .husky/pre-commit "npx validate-a11y"Or create .husky/pre-commit manually:
#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"
echo "Running accessibility check..."
npx validate-a11y || exit 1Make it executable (Mac/Linux): chmod +x .husky/pre-commit
Option 2 — Manual Git hook
#!/usr/bin/env sh
# .git/hooks/pre-commit
npx validate-a11y || exit 1chmod +x .git/hooks/pre-commitOption 3 — npm script only
{ "scripts": { "validate-a11y": "validate-a11y" } }🔄 Workflow
git add . ← Stage your files
│
▼
git commit -m "your message" ← Triggers the hook automatically
│
▼
♿ a11y-commit-validator runs
│
├── Detects staged .html / .jsx / .js / .liquid files
├── Scans each file for WCAG violations
├── Calls AI for WHY + FIX (Groq → GitHub Models → OpenAI → built-in fallback)
│
├── ✅ No issues? → Commit goes through
└── ❌ Issues found? → Commit BLOCKED
Auto-fix or fix manually
git add . && git commit again📋 Rules checked
24 custom rules — grouped by WCAG Success Criterion. All run on .liquid and .html. Rules marked ⚛️ also run on .jsx/.js (alongside the richer ESLint AST versions).
SC 1.1.1 — Non-text Content
| Rule ID | Severity | What it catches |
|---|---|---|
| img-missing-alt ⚛️ | 🔴 Critical | <img> with no alt attribute |
| img-empty-alt ⚛️ | 🔴 Critical | <img alt=""> on a meaningful image |
SC 1.2.2 — Captions (Prerecorded)
| Rule ID | Severity | What it catches |
|---|---|---|
| video-missing-captions | 🔴 Critical | <video> with no <track kind="captions"> |
SC 1.3.1 — Info and Relationships
| Rule ID | Severity | What it catches |
|---|---|---|
| table-missing-headers | 🟡 Warning | <table> with no <th> or scope attribute |
SC 1.4.1 — Use of Color
| Rule ID | Severity | What it catches |
|---|---|---|
| link-underline-removed | 🟡 Warning | <a style="text-decoration:none"> — links relying on colour alone |
SC 1.4.2 — Audio Control
| Rule ID | Severity | What it catches |
|---|---|---|
| autoplay-media | 🟡 Warning | <audio> or <video autoplay> |
SC 2.4.6 — Headings and Labels
| Rule ID | Severity | What it catches |
|---|---|---|
| empty-heading ⚛️ | 🔴 Critical | <h1>–<h6> with no text content |
SC 2.4.7 — Focus Visible
| Rule ID | Severity | What it catches |
|---|---|---|
| focus-outline-removed | 🔴 Critical | :focus { outline: none/0 } in style blocks |
| inline-outline-removed | 🔴 Critical | style="outline:none" inline |
SC 3.3.2 — Labels or Instructions
| Rule ID | Severity | What it catches |
|---|---|---|
| input-missing-label ⚛️ | 🔴 Critical | <input> with no aria-label or id |
| select-missing-label ⚛️ | 🔴 Critical | <select> with no aria-label or id |
| textarea-missing-label ⚛️ | 🔴 Critical | <textarea> with no aria-label or id |
SC 4.1.1 — Parsing
| Rule ID | Severity | What it catches |
|---|---|---|
| duplicate-id | 🔴 Critical | Duplicate id attribute values in one file |
SC 4.1.2 — Name, Role, Value
| Rule ID | Severity | What it catches |
|---|---|---|
| button-missing-label ⚛️ | 🔴 Critical | <button></button> with no accessible name |
| anchor-missing-label ⚛️ | 🔴 Critical | <a></a> with no text or aria-label |
| html-missing-lang ⚛️ | 🔴 Critical | <html> missing lang attribute |
| custom-control-missing-label | 🔴 Critical | Element with interactive role= but no aria-label/aria-labelledby/title |
| aria-hidden-focusable | 🔴 Critical | aria-hidden="true" on a focusable element (<a>, <button>, <input>, etc.) |
| iframe-missing-title ⚛️ | 🔴 Critical | <iframe> with no title attribute |
General / Deprecated
| Rule ID | Severity | What it catches |
|---|---|---|
| marquee-tag | 🔴 Critical | Deprecated <marquee> element |
| blink-tag | 🔴 Critical | Deprecated <blink> element |
| onclick-non-interactive | 🟡 Warning | onClick on a non-interactive <div> or <span> |
| aria-expanded-static | 🔵 Info | aria-expanded hardcoded to "true"/"false" |
| tabindex-positive | 🔵 Info | tabindex value greater than 0 |
Plus all axe-core WCAG 2.0 / 2.1 / 2.2 rules for .html files and all eslint-plugin-jsx-a11y recommended rules for .jsx / .js files — bringing the total coverage to 87 WCAG success criteria.
📂 Supported file types
| Extension | Scanner used |
|---|---|
| .html | axe-core via jsdom (full WCAG 2.2 audit) |
| .jsx | eslint-plugin-jsx-a11y + regex rules |
| .js | eslint-plugin-jsx-a11y + regex rules |
| .liquid | Regex rules |
🤖 AI-Powered Analysis
For each violation the AI provides:
- WHY — One sentence explaining exactly how this harms disabled users
- FIX — A corrected, ready-to-paste snippet specific to your actual code
The analysis is powered by whichever provider you configure — the tool picks the first available one automatically.
�️ See it in action
Drop it in, stage your files, and commit. This is what you'll see:
① Startup & file detection
┌──────────────────────────────────────────────────────────┐
│ ♿ A11Y COMMIT VALIDATOR v2.0.2 │
│ 🤖 Powered by Groq AI │
└──────────────────────────────────────────────────────────┘
✔ Found 2 file(s) to scan
📄 src/components/ProductCard.jsx
📄 src/sections/Hero.jsx② Live scan with progress bar
Scanning files:
[01/02] ████████████████░░░░░░░░░░░░░░ 53% ProductCard.jsx
[02/02] ██████████████████████████████ 100% Hero.jsx
✖ Scan complete — 3 issue(s) found! (1 duplicate removed)③ AI steps in (whichever provider is configured — Groq shown here)
🤖 Groq AI analysis complete.④ Red alert — issues detected
////////////////////////////////////////////////////////////////
// ♿ ACCESSIBILITY ISSUES DETECTED //
////////////////////////////////////////////////////////////////
Summary: 🔴 2 Critical 🟡 1 Warning 🔵 0 Info (3 total)
🔧 3 auto-fixable (AI-enhanced)⑤ Per-issue breakdown
──────────────────────────────────────────────────────────
[01] 🔴 CRITICAL jsx-a11y/alt-text Line 9
src/components/ProductCard.jsx
Why Images without alt text are completely invisible to screen
readers, locking out millions of visually impaired users.
Fix <img src={product.image} alt={product.title} className="card__img" />
[02] 🔴 CRITICAL jsx-a11y/click-events-have-key-events Line 18
src/components/ProductCard.jsx
Why A click-only handler locks out keyboard and switch-device
users who cannot use a mouse — WCAG 2.1 failure.
Fix <div role="button" tabIndex={0} onClick={...} onKeyDown={...}>
[03] 🟡 WARNING jsx-a11y/label-has-associated-control Line 34
src/sections/Hero.jsx
Why A form input with no associated label is unreadable by screen
readers — users won't know what the field is for.
Fix <label htmlFor="email">Email address</label>
<input id="email" type="email" />
──────────────────────────────────────────────────────────⑥ Interactive auto-fix prompt
╔══════════════════════════════╗
║ 🔧 AUTO-FIX AVAILABLE ║
╚══════════════════════════════╝
Groq AI has suggested fixes for 3 of the 3 issue(s) found.
What would you like to do?
[1] ✅ Apply all fixes automatically
[2] 🔍 Review & apply fixes one by one
[3] ⏭️ Skip — I'll fix them manually
Enter choice (1-3): 1
✅ Applied 3/3 fix(es) and re-staged the affected file(s).⑦ All clean
✅ ALL ACCESSIBILITY CHECKS PASSED!
All validators passed! Committing...🔧 Troubleshooting
No staged files detected
Run
git add <file>before committing. Only staged files are scanned.
SSL certificate error (corporate networks)
npm error UNABLE_TO_GET_ISSUER_CERT_LOCALLYRun once:
npm config set strict-ssl false
Groq API unavailable
Falls back to built-in suggestions automatically. No action needed.
🔌 Programmatic API
const { run } = require('a11y-commit-validator');
await run();const { scanFile } = require('a11y-commit-validator/src/scanner');
const issues = await scanFile('src/index.html');
// [{ file, ruleId, description, match, lineNumber, wcag }]// Enhance issues with AI suggestions (uses whichever provider key is in .env)
const { enhanceWithCopilot } = require('a11y-commit-validator/src/copilot');
const enhanced = await enhanceWithCopilot(issues);
// [{ ...issue, copilotWhy, copilotFix }] — Groq / GitHub Models / OpenAI / built-inconst { applyAllFixes } = require('a11y-commit-validator/src/fixer');
const { applied, failed, total } = applyAllFixes(enhanced);🆕 What's new in v2.0.0
- 🤖 Groq AI integration — Free LLaMA 3.3 70B, no credit card needed
- Auto-fix engine — Apply AI-suggested fixes from the terminal, files re-staged automatically
- 🎨 Simplified terminal output — Cleaner, focused issue display
- 🐛 Fixed duplicate output bug — HOW TO FIX section prints exactly once
- 🔒 Safer AI fixes — Constrained to single-line changes, prevents broken JSX
📈 Roadmap
- [ ] VS Code extension integration
- [ ] Support for Vue
.vuesingle-file components - [ ] WCAG 3.0 rules (when finalised)
- [ ] Custom rule configuration via
.a11yrc.json - [ ] GitHub Actions / CI mode
- [ ] Support for
.svelteand.astrofiles
🤝 Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Commit:
git commit -m "Add my feature" - Push and open a Pull Request
📋 Requirements
- Node.js: >= 16.0.0
- Git: Any recent version
- AI Provider: Optional — add one key to
.env. Groq is free (console.groq.com). GitHub Models and OpenAI also supported. Falls back to built-in suggestions if none configured
🙏 Acknowledgments
- axe-core — The gold standard for accessibility auditing
- eslint-plugin-jsx-a11y — AST-level JSX rules
- Groq — Free, blazing-fast LLaMA inference
- The open-source accessibility community
📜 License
MIT
