I Built a WCAG 2.2 Accessibility Checker and Shipped Its SDK to Three Package Registries as a CS Student
Most of my college projects lived and died on a USB drive. This one ended up on NuGet, npm, and Cargo. Here's how it happened and what I learned.
The Problem
While working on a web project, I wanted to check if my site was accessible. Every tool I found was either a browser extension that was useless for CI, a paid SaaS, or a basic linter that didn't handle JavaScript-rendered content at all.
WCAG 2.2 had just introduced new criteria — target size minimums, redundant entry prevention — and nothing free was checking for those yet. So I built my own.
What I Built
AXIS is a desktop accessibility auditor for Windows that renders JavaScript-heavy pages using a headless Chrome engine, audits against WCAG 2.2, WCAG 2.1, Section 508, and India's RPwD Act, scores pages from 0–100 with a compliance tier, estimates the page's carbon footprint, and exports TXT and PDF reports.
But the more interesting part was what came next.
The SDK Idea
Once the core audit engine was working, I realized it was completely decoupled from the UI. So I extracted it into AXIS-CORE — a standalone library that any developer could drop into their own tooling or CI/CD pipeline.
var checker = new AxisCore();
var report = await checker.CheckUrlAsync("https://example.com");
Console.WriteLine($"Score: {report.AccessibilityScore}/100");
Then I thought — why stop at .NET?
Shipping to Three Registries
I ported the SDK to JavaScript and Rust, and published all three:
| Runtime | Package |
|---|---|
| .NET | AXIS-CORE on NuGet |
| JavaScript | axis-core-sdk on npm |
| Rust | axis-core on Cargo |
Each one went through the full publish cycle — versioning, package metadata, README, API surface design. It took longer than I expected. Way longer.
What I didn't expect
Publishing to NuGet is surprisingly strict compared to npm. You need proper package metadata, a valid license SPDX expression, and a README that actually renders correctly in their portal. My first few attempts were rejected silently — the package appeared listed but showed no description.
Cargo was the smoothest. The cargo publish workflow is well-documented and the tooling catches most mistakes before you even push.
npm was the fastest to publish but the hardest to get right structurally. CommonJS vs ESM compatibility and making sure the package resolves correctly across Node versions took a few iterations.
WCAG 2.2 — What's Actually New
This was the part I had to research most deeply. Two new criteria stood out.
2.5.8 — Target Size Minimum (Level AA)
Clickable elements need a minimum area of 24×24 CSS pixels. Sounds obvious, but a surprising number of icon buttons and inline links fail this.
button, a {
min-width: 24px;
min-height: 24px;
padding: 8px 12px;
}
3.3.7 — Redundant Entry (Level A)
Forms collecting personal data must use autocomplete attributes. This one is almost universally ignored.
<input type="email" name="email" autocomplete="email">
<input type="tel" name="phone" autocomplete="tel">
AXIS checks both automatically.
The Environmental Angle
One feature I added on a whim turned out to be the most talked-about when I demoed it — a carbon footprint estimate per page load.
It factors in page weight, request count, CDN usage, and estimated server energy draw, then gives a rating:
| Rating | CO₂ per page load |
|---|---|
| 🌱 Eco | < 10 g |
| 🟡 Moderate | 10 – 50 g |
| 🔴 High Impact | > 50 g |
It's not scientific-grade, but it makes people think — which was the point.
What I Learned
Designing a public API is hard. When it's just your own app, you can change internals freely. Once it's a published package, breaking changes have real consequences. I had to think carefully about naming, return types, and async patterns before publishing v1.
Documentation is the product. Nobody will use your package if the README doesn't immediately show them what it does and how to install it. I rewrote the README three times.
Multi-runtime is a commitment. Keeping three SDKs in sync across .NET, JavaScript, and Rust means any core logic change needs to propagate to all three. I underestimated this. Python support is planned but I'm being careful about when I take that on.
Organic downloads feel different. Seeing strangers install something you built without you telling them to is a genuinely different feeling from a project that only your professor sees.
What's Next
Python SDK on PyPI, a GitHub Actions integration so teams can run AXIS checks in CI without writing any code, and a VS Code extension companion — A11Y: Lazy Edition is already live for in-editor checks.
Try it
- Release
-
NuGet:
dotnet add package AXIS-CORE -
npm:
npm install axis-core-sdk -
Cargo:
cargo add axis-core
If you're building anything where accessibility matters or just want to know your page's carbon footprint, give it a try. And if you've shipped a multi-runtime SDK before, I'd love to know how you handled keeping them in sync.
Built with WPF · .NET 9 · C# · HtmlAgilityPack · PuppeteerSharp · QuestPDF
Main changes: collapsed the bullet-heavy "What's Next" into a paragraph, merged the fragmented "What I Learned" bullets into flowing prose, and removed the section separators that were making it feel templated.
Top comments (0)