Automating Accessibility Checks for Documentation
API documentation has an accessibility problem: it's often written by developers who haven't thought about screen readers, keyboard navigation, or color contrast. This post explains how DocsCI integrates axe-core and structural validation to catch accessibility issues in CI — before they reach users.
Why documentation accessibility matters
Developer documentation is used by developers with disabilities: screen reader users, keyboard-only users, users with low vision who rely on high contrast, users with cognitive disabilities who rely on clear heading structure to navigate long reference pages. Documentation that fails basic accessibility standards excludes a non-trivial portion of your potential developer audience.
Beyond ethics, documentation accessibility is increasingly a procurement requirement. Enterprise customers (particularly government, healthcare, and finance) often require WCAG 2.1 AA compliance as part of vendor evaluation. Documentation with known accessibility violations can block a deal.
The practical problem: most documentation accessibility issues are caught late — by a user filing a complaint, or by a manual audit done once every six months. DocsCI brings accessibility checks into the CI pipeline, so they're caught on the PR that introduces them.
Two layers of checks
DocsCI runs accessibility validation at two levels, which together cover the bulk of real-world documentation accessibility issues:
Layer 1: Structural (source-level)
These checks run directly on the Markdown/MDX/RST source without rendering. They're fast, deterministic, and catch structural issues that rendering won't help diagnose:
Heading hierarchy
Detects skipped heading levels (H1 → H3 without H2). Screen readers use heading structure as the primary navigation mechanism for long pages.
# Page title ### Section (skipped H2) ← violation
# Page title ## Section ### Subsection
Image alt text
Flags images without alt text, or with non-descriptive alt text ('image', 'screenshot', 'logo' without context).
 ← missing alt text

Link text quality
Flags generic link text ('click here', 'read more', 'this link'). Screen reader users often navigate by link list, where context is stripped.
[Click here](https://snippetci.com/signup) for early access
[Get DocsCI early access](https://snippetci.com/signup)
Code block language hints
Flags code blocks without language annotations. Screen readers and syntax highlighters need the language tag to describe code content correctly.
``` curl -X POST ... ```
```bash curl -X POST ... ```
Layer 2: axe-core (rendered)
For documentation sites that render their Markdown to HTML (Docusaurus, Mintlify, ReadMe, etc.), DocsCI can run axe-core against the rendered output. axe-core is the industry-standard accessibility testing engine used by Deque, Lighthouse, and Jest-axe.
// DocsCI axe-core integration (simplified)
import { JSDOM } from "jsdom";
import axe from "axe-core";
async function checkRenderedPage(htmlContent: string, url: string) {
const dom = new JSDOM(htmlContent, { url });
const window = dom.window;
// Configure axe for docs-specific rules
const axeConfig = {
rules: {
"color-contrast": { enabled: true },
"heading-order": { enabled: true },
"image-alt": { enabled: true },
"link-name": { enabled: true },
"landmark-one-main": { enabled: false }, // docs often lack <main>
"region": { enabled: false }, // docs often use divs
},
resultTypes: ["violations", "incomplete"],
};
const results = await axe.run(window.document, axeConfig);
return results.violations.map(v => ({
id: v.id,
impact: v.impact, // "critical", "serious", "moderate", "minor"
description: v.description,
nodes: v.nodes.map(n => ({
html: n.html.substring(0, 200),
selector: n.target.join(" > "),
failureSummary: n.failureSummary,
})),
}));
}axe-core catches things that structural analysis can't: rendered color contrast failures (where CSS variables determine the actual color), ARIA role mismatches in component-rendered docs, and focus trap issues in interactive doc widgets.
What DocsCI reports
Each accessibility finding is reported as a PR comment with the exact file, line (for structural checks), or element selector (for axe-core), the WCAG criterion that was violated, and a suggested fix:
## ♿ DocsCI Accessibility — docs/quickstart.md:23 **Rule:** heading-order (WCAG 1.3.1 — Info and Relationships) **Impact:** moderate **Issue:** Heading jumps from H2 to H4 without H3 between them. ```diff ## Authentication - #### Setting API keys + ### Setting API keys ``` --- ## ♿ DocsCI Accessibility — docs/reference/users.md:67 **Rule:** image-alt (WCAG 1.1.1 — Non-text Content) **Impact:** critical **Issue:** Image has no alt attribute. ```diff -  +  ```
Enabling accessibility checks
In your docsci.yml, set accessibility: true:
# docsci.yml
checks:
snippets: true
drift: true
accessibility: true # enable structural a11y checks
copy_lint: false
# Accessibility rule config (optional)
accessibility:
# Structural rules (source-level)
heading_hierarchy: true
image_alt: true
link_text: true
code_block_language: warn # "error" | "warn" | false
# Rendered checks (requires docs_site_url in CI)
axe_core: false # enable if you render doc pages
# WCAG level: "A", "AA", "AAA"
wcag_level: "AA"
# Allow specific violations (e.g., known third-party components)
# allow:
# - { rule: "color-contrast", selector: ".third-party-widget" }Practical impact
In our beta testing with 8 documentation teams, enabling accessibility checks on first run found a median of 14 issues per repo — mostly heading hierarchy violations and images without alt text. After a single sprint of fixes, all 8 teams maintained zero accessibility regressions in subsequent PRs for 3+ months.
The biggest impact came from heading order checks. API reference pages often have complex heading structures that drift over time as sections are added and reorganized. Catching heading hierarchy violations in PR review takes 30 seconds per finding. Fixing them after a user with a screen reader files a complaint takes an afternoon of audit work.
Add accessibility checks to your docs CI
Free tier includes structural accessibility checks on all plan sizes.