npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

aria-reach

v0.1.1

Published

Static analyzer for ARIA anti-patterns in shared component libraries, with npm reach (Library Reach Index) scoring. Reference implementation of the four-class ARIA anti-pattern taxonomy.

Readme

aria-reach

Static analyzer for ARIA anti-patterns in shared component libraries, with npm reach scoring to prioritize the fixes that help the most assistive-technology users.

Most accessibility checkers audit applications. aria-reach targets the layer above them: the shared component libraries (UI kits, editors, media players, form frameworks) whose ARIA defects silently propagate into every downstream application that imports them. One upstream fix repairs every consumer at once — so that is where audit effort pays off most.

aria-reach is the reference implementation of the four-class ARIA anti-pattern taxonomy from the paper "ARIA Anti-Patterns in Shared Component Libraries: A Taxonomy and Force-Multiplied Remediation Strategy for Screen Reader Accessibility" (under review; preprint link forthcoming). Each rule is grounded in a real upstream contribution to a major library.

Install

npm install -g aria-reach   # or: npx aria-reach ...

Build from source (for contributors):

git clone https://github.com/manichandra/aria-reach.git
cd aria-reach && npm install && npm run build
node dist/cli.js scan src/

New here? Follow the worked example in GETTING_STARTED.md.

Scan templates for anti-patterns

aria-reach scan src/                  # .html/.htm + inline Angular templates in .ts/.js
aria-reach scan src/ --json           # machine-readable output

Exit code is 1 when any error-severity finding is reported, so it can gate CI.

Use in CI (GitHub Action)

# .github/workflows/accessibility.yml
name: accessibility
on: [push, pull_request]
jobs:
  aria-reach:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: manichandra/[email protected]
        with:
          path: src            # file(s)/dir(s) to scan, space-separated
          # json: true         # machine-readable output
          # fail-on-error: false   # report-only, don't fail the job

The job fails when any error-severity ARIA finding is reported. GitHub-hosted runners already include Node ≥ 18.

Angular binding syntax is understood: [attr.aria-hidden]="expr" counts as the attribute being handled, and statically-unknowable bound values are never false-flagged. Inline component templates (template: \…`) are extracted from .ts/.js` sources with line numbers mapped back to the source file — scanning PrimeNG's real library source yields 172 findings across 51 component files.

Scan any live page — runtime mode (framework-agnostic)

The same rules run against the rendered DOM of any app (React, Vue, Angular, vanilla — at runtime it's all DOM), with upstream library attribution: findings are labeled with their likely origin (PrimeNG, Angular Material, Quill, Video.js, USWDS, MUI, Ant Design, …) so they can be fixed upstream where one fix reaches every consumer.

  • Console snippet: paste dist/aria-reach.browser.js (built via npm run build:browser) into any DevTools console → grouped report + window.ariaReach.scan()/.report()/.summary(). Works in Chrome, Edge, Firefox, and Safari.
  • Browser extension: npm run build:ext, then load browser-extension/ unpacked in Chrome; Safari via Xcode's safari-web-extension-converter. See browser-extension/README.md.

The four anti-pattern classes

| Class | Anti-pattern | WCAG / ARIA | Grounding contribution | |---|---|---|---| | I | Decorative Noise Injection — separators/icons exposed to the accessibility tree | SC 1.1.1, 4.1.2 | PrimeNG breadcrumb separators (primefaces/primeng#19568) | | II | Live Region Urgency Miscalibration — assertive where polite belongs | SC 4.1.3 | Video.js description tracks (videojs/video.js#9178) | | III | Widget Role Contract Violations — wrong/incomplete role, state, or property | SC 4.1.2, WAI-ARIA APG | Quill listbox pattern (slab/quill#4807), Angular Material calendar aria-pressedaria-selected (angular/components#33235) | | IV | Async State Desynchronization — submission outruns async validation | SC 3.3.1, 3.3.4 | Angular Forms awaitAsyncValidators (angular/angular#68661) |

Rules

| Rule | Class | Default severity | |---|---|---| | decorative-separator-aria-hidden | I | error / warning | | svg-decorative-aria-hidden | I | warning | | assertive-live-region-review | II | warning / info | | listbox-missing-options | III | error | | option-missing-aria-selected | III | error | | aria-pressed-in-selection-context | III | error | | haspopup-missing-aria-expanded | III | warning | | ngsubmit-await-async-validators | IV | info |

Reach scoring (Library Reach Index)

Quantify how far an upstream fix travels before you spend review effort:

aria-reach reach primeng quill video.js @angular/forms @angular/material
Library Reach Index (LRI = weekly downloads x A-hat)

package                 downloads/week   A-hat   LRI (est. deployments)
primeng                      2,012,345     0.1                  201,234
...

LRI(L) = Dw(L) × Â(L) — weekly npm downloads times an estimated deployments-per-download coefficient (--a-hat, default 0.1). The LRI is an order-of-magnitude prioritization instrument, not a precise measurement: libraries with high LRI are the highest-leverage targets for upstream accessibility contribution.

Library API

import { scanPaths, scanSource, reach } from 'aria-reach';

const findings = scanPaths(['src/']);            // Finding[]
const inline = scanSource('<span>›</span>', 'x.html');
const rows = await reach(['primeng'], 0.1);      // ReachRow[]

Limitations (read this)

Static analysis sees annotated-but-wrong patterns; it cannot prove a custom widget lacking all semantics is interactive, cannot evaluate bound expressions, and cannot replace runtime checkers (axe-core) or manual screen-reader testing (NVDA/JAWS/VoiceOver). Class IV detection is a heuristic: it flags the opportunity for desynchronization, not a proven defect. Use aria-reach as the library-layer complement to — never a substitute for — application-layer audits and AT testing.

Framework support

| Surface | Static CLI | Runtime (snippet/extension) | |---|---|---| | Plain HTML | ✅ | ✅ | | Angular templates (external + inline, binding syntax) | ✅ | ✅ (rendered) | | React (JSX), Vue (SFC), Svelte | ⏳ roadmap | ✅ (rendered DOM) | | Any page in a browser | — | ✅ |

The taxonomy is framework-agnostic (two of the five grounding case studies — Video.js and Quill — are vanilla JS). The static CLI started Angular-first because that ecosystem hosts the grounding contributions; runtime mode covers everything else today.

Roadmap

  • Chrome DevTools panel (inspect-element integration; Safari lacks the devtools WebExtensions API, so Safari keeps the popup)
  • Dependency-graph propagation: enumerate downstream consumers affected by a library-level finding ("npm audit for accessibility")
  • Class IV control-flow analysis of TypeScript component sources (async validator registration vs. submit paths)
  • React/JSX and Vue SFC template extraction for the static CLI
  • SARIF output for CI annotation

Author

Manichandra Sajjanapu — personal open-source project; not affiliated with or representing any employer. MIT licensed. Contributions welcome.