Scoring

The scoring model exists to be argued with

Every input to every score is published. If you dislike the weightings you can recompute the whole index with your own.

The scoring model exists to be argued with. Every input is published, so anyone who dislikes our weightings can recompute the whole index with their own.

Statuses

Statuses
StatusMeaningCounts toward score
passBehaviour matched the assertionYes
failBehaviour did not matchYes
not-applicableThe pattern genuinely does not apply to this libraryNo
errorThe assertion could not be evaluated, harness or runner faultNo

error never counts. If we could not run a check, that is our problem and we do not get to score someone down for it. A run with any error is flagged in the UI and is not eligible for publication until resolved.

Severity weights

Severity weights
SeverityWeightDefinition
blocker10A user relying on this input method cannot complete the task at all
serious5The task is completable but confusing, or state is not communicated
moderate2Behaviour departs from the specified pattern; users are inconvenienced
minor1Technically non-conforming, low practical impact

Severity is a property of the assertion, fixed at authoring time, not adjusted per library after seeing results. Changing a severity is a spec version bump and goes in DECISIONS.md with a reason.

Formula

score = 100 × (Σ weight of passed assertions) / (Σ weight of applicable assertions)

Applicable = pass + fail. That is the whole calculation. It is deliberately simple enough to verify by hand from the published JSON, a scoring model nobody can check is a scoring model nobody should trust.

Presentation rules

These are not cosmetic preferences. They are the difference between a useful reference and a misleading one.

Never lead with the aggregate number. The headline unit is a component, not a library. "Radix Dialog: 11/12" is a claim we can defend. "Radix: 94%" is close to meaningless, because it averages across components with wildly different maturity.

Always show the blocker count separately. A library with one blocker and thirty passes scores well and is still unusable for someone navigating by keyboard. A weighted average cannot express that, so the blocker count is displayed next to every score, always.

Always pin the version. @radix-ui/react-dialog@1.1.4, never "Radix". Scores describe a version, not a project.

Always link the evidence. Every failure links to the APG clause, the WCAG success criterion, a reproduction URL, and a downloadable Playwright trace. A failure a reader cannot verify themselves should not be published.

Always state the ceiling. On every page:

A high score means no violations were detected by automated testing. It does not mean the component is accessible. Automated tests cannot evaluate whether a label is meaningful, whether a reading order makes sense, or whether the experience is genuinely usable with a screen reader. Those require human judgement and disabled users. This project is a floor, not a ceiling.

That paragraph is not a disclaimer to be tucked into a footer. It is the honest description of what automated conformance testing is, and stating it prominently is what separates this from the compliance-theatre tools that gave automated accessibility testing a bad name.

What is deliberately not scored

  • Documentation quality. Real signal, not measurable by this harness.
  • Bundle size, API ergonomics, styling. Not our remit; there are better tools.
  • Effort or intent. A library maintained by two volunteers and one funded by a large company are scored identically, because a keyboard user's experience does not depend on the maintainer's headcount. Context belongs in the writeup, not the number.

Regressions

Every result is stored against its version, so the index carries history:

@radix-ui/react-dialog
  1.1.2  ██████████ 100%
  1.1.3  ██████████ 100%
  1.1.4  ████████░░  83%  ← regression: dialog.focus-restored

This is the most valuable output of the project and it only exists because results are versioned and continuous. A regression alert is worth more to a maintainer than any league table, and it is the thing that makes the index worth subscribing to rather than reading once.

This page is generated from docs/SCORING.md in the repository. If the two ever disagree, the repository is right.