axe-core finds the accessibility bugs it can prove, and quietly hands you the other half as homework
By The bee2.io Engineering Team at bee2.io LLC

Run axe-core against a page and get zero violations back, and the temptation is to treat that as a clean bill of health. Read the project's own numbers and that temptation collapses: axe-core's maintainers say it catches, on average, 57% of WCAG issues automatically. That is an average across issue sets, not a per-page promise or an upper limit. Whatever automation cannot decide still needs a human to look, or appears as "incomplete" so a person can finish the job. A green report is not a certificate of accessibility. It is a receipt for the slice of the job a script can actually do.
That gap is the whole design story of axe-core. It is a JavaScript rule engine, built and maintained by Deque Systems, that runs inside a browser context - real or automated - and inspects the live DOM against a library of accessibility checks. You install it, drop axe.js or axe.min.js onto the page under test, and call axe.run(), which returns a promise of results you inspect for violations and incomplete findings. Nothing exotic. The interesting decisions are all in what the checks are willing to claim.
The zero-false-positives promise, and what it actually costs
axe-core's manifesto states plainly that it "returns zero false positives (bugs notwithstanding)." That is a real design constraint, not marketing filler: a rule that can't be certain does not fail the element, it marks it "incomplete" and asks a person to decide. Contrast that with a linter that flags anything remotely suspicious and lets you triage the noise.
The tradeoff is coverage. Checks that would risk false positives get pushed into "incomplete" or left out of automation entirely. That conservatism helps explain the maintainers' average 57% automatic-detection figure; actual coverage varies with the issue set. Rules cover WCAG 2.0, 2.1 and 2.2 at levels A, AA and AAA, plus best-practice checks for common structural and ARIA mistakes.
The full catalogue lives in the repo's rule-descriptions document and is worth reading once, because "no violations" quietly means something narrower than most stakeholders assume.
How it actually gets wired into a pipeline
The API is deliberately unglamorous. axe.run() returns a promise whose resolved result includes both violations and incomplete. A test runner must wait for that promise, fail on relevant violations, and surface incomplete findings for manual review. Starting the scan and allowing the runner to finish first merely tests the event loop's capacity for optimism.
const results = await axe.run();
if (results.violations.length) {
throw new Error('Accessibility issues found');
}
if (results.incomplete.length) {
console.warn('Accessibility checks need manual review', results.incomplete);
}
That's the whole contract: promise in, structured result out. axe-core also supports in-memory and static fixtures, integration tests, and deeply nested iframes, so it can follow modern interfaces through considerably more DOM machinery than a quick glance at the initial document would suggest.
axe-core targets modern browsers and a wide range of testing environments. The current support matrix belongs in the project's API documentation rather than in a forever-copied list, because browser and test coverage changes. JSDOM receives limited support, with one important exception below.
Licensing is MPL-2.0, which people skip until legal asks. Its file-level copyleft allows axe-core to sit in a larger proprietary product without opening unrelated files. But if you distribute the MPL-covered code in executable form, you must make its corresponding source form - including modifications to covered files - available under MPL-2.0, preserve required notices, and tell recipients how to obtain that source.
Separate proprietary files may retain their own terms, provided those terms do not restrict recipients' MPL rights in the covered code. "We didn't relicense axe-core" is not a compliance plan; it is barely the first sentence.
Locale is a first-class config, not an afterthought
axe-core supports translated message catalogues under ./locales. Locale data can also be supplied at runtime through the locale property passed to axe.configure(). If your team ships a German or Japanese admin console, the accessibility error text can match, instead of forcing bilingual QA to read English stack-trace-flavored strings.
Keeping up with releases without getting burned
New axe-core versions can introduce rules, features, and fixes, which means a pinned old version may miss issues that later checks learned to detect. Security maintenance is not indefinite either. Schedule upgrades, consult the project's release and support documentation, and treat a stale pin as technical debt rather than a treasured family heirloom.
Where this goes sideways
Contrast checks cannot be trusted under JSDOM. If your accessibility tests run inside Jest with JSDOM instead of a real or headless browser, the color-contrast rule is explicitly identified in axe-core's documentation as not working there. Do not interpret a clean JSDOM run as evidence that contrast passed.
Run any suite that relies on color-contrast in an actual browser engine, or disable that rule under JSDOM and cover contrast in a browser-based pass. Otherwise the button-on-background contrast bug ships while the test suite sits nearby looking innocent.
Cross-origin iframe coverage needs to be verified, not assumed. axe-core supports nested iframes, but that broad capability is not permission to assume every third-party embed was inspected. Browser origin boundaries and how the testing code reaches each frame still matter.
Surface all incomplete findings, audit third-party embeds separately, and run axe-core against the embedded page directly when you control it. A pipeline that displays only violations hides precisely the uncertainty a human needs to investigate.
"Zero violations" gets read as "accessible" by people who never saw the 57% figure. This isn't a bug, it's a documentation gap between what engineering reports and what everyone downstream assumes it means. A PM sees a green accessibility gate and closes the ticket; a screen reader user hits a completely unlabelled custom dropdown three sprints later.
Report incomplete results as required manual-review items in the same tracker as violations, not as a footnote, and pair axe-core with actual assistive-technology testing before calling anything done.
Browser-specific bugs surface late when testing relies on one engine. An axe-core pass in one browser does not establish that the interface behaves correctly across every browser your product supports. Browser engines and accessibility mappings differ, and automation cannot turn a narrow test matrix into a broad one through positive thinking.
Run accessibility checks across the browsers in your product's support policy where practical, and budget targeted manual testing for the remaining combinations. Treat a passing CI run as evidence about the environments it actually exercised, not cross-browser proof.
References
- Repository and README: https://github.com/dequelabs/axe-core
- Package page: https://www.npmjs.com/package/axe-core
- Rule descriptions: https://github.com/dequelabs/axe-core/blob/develop/doc/rule-descriptions.md
- Release and support documentation: https://github.com/dequelabs/axe-core/blob/develop/doc/release-and-support.md
- axe-linter VS Code extension: https://marketplace.visualstudio.com/items?itemName=deque-systems.vscode-axe-linter
- axe browser extension ("intelligent guided tests"): https://www.deque.com/axe/browser-extensions/
Important notice. Tap any item to read it in full.
Accuracy is not guaranteed
This article was produced with substantial automated assistance and is published without individual expert verification of every statement. It may contain errors, omissions, oversimplifications, or claims that were accurate when written and have since been superseded. Software, protocols, specifications and best practice in this field change quickly.
Verify before you rely on it
Treat this page as a starting point and a pointer to primary sources, never as an authority in itself. Before acting on anything here, check it against the official documentation, the original publication, or the vendor's own materials, which are linked in the references above. Where this page and a primary source disagree, the primary source is correct and this page is wrong.
No warranty
This content is provided "as is", without warranty of any kind, express or implied, including but not limited to warranties of accuracy, completeness, currency, merchantability, or fitness for a particular purpose.
No liability
To the fullest extent permitted by applicable law, scoutb2.io and its authors accept no liability for any loss or damage whatsoever, whether direct, indirect, incidental, consequential or otherwise, arising from use of or reliance on this article. This expressly includes lost time, lost data, damaged samples or specimens, wasted reagents or compute, failed experiments, equipment damage, and commercial loss.
Not professional advice
Nothing here constitutes professional, scientific, engineering, regulatory, safety or legal advice. You remain solely responsible for your own experimental design, safety assessment, regulatory compliance and data handling, and for any code you run or procedure you perform.
About the illustration
Any image accompanying this article is editorial and decorative. It was produced with generative AI, is not a technical diagram, is not to scale, and is not an accurate depiction of any structure, process or result. Do not read measurements, structures or relationships from it.
Third-party names and links
Product, project and organisation names are the property of their respective owners and are used for identification only. Their mention is not endorsement, affiliation or sponsorship in either direction. External links are provided for convenience and we neither control nor are responsible for third-party content.
Corrections
If you find an error, tell us and we will correct or withdraw the page.
Stop finding issues manually
SCOUTb2 scans your entire site for accessibility, performance, and SEO problems automatically.