River
Y CombinatorBacked by Y Combinator
FREE TEMPLATE

Accessibility Audit Remediation Plan

Your audit reports one row per occurrence. This regroups every selector by the component that rendered it, which is where the work actually is.

Free download  ·  No account needed

An accessibility audit arrives as one row per occurrence. Page URL, CSS selector, rule id, impact. Sorted by page, 4,812 findings across 340 pages look like 340 projects, the worst page has sixty-one findings, and the next page has fifty-eight caused by the same four components. That is the shape a scanner has to produce and the shape no team can schedule, which is why most audits are read once and filed in a folder nobody opens again.

This pack resolves every selector to the component that rendered it and regroups the whole export by component. The same 4,812 findings become twelve components, six of which carry 4,329 of the findings and add up to roughly two working days. That concentration is structural rather than lucky: WebAIM's survey of the top million home pages finds that ninety-six percent of detected errors fall into six categories, and the same six have led the list for seven straight years.

So the plan comes out as pull requests with owners, effort and an acceptance criterion, ordered by whether the barrier blocks a task rather than by how many times it appears. It is the same move the vulnerability triage pack makes on a scanner export, and it feeds the roadmap pack once the work needs a quarter. Which components anybody actually uses comes from the adoption review, or download the pack as Word and CSV files.

The same audit, grouped by the thing you can actually change

Every count in Priority by User Impact and Retest Tracking recomputes from the register. Nothing on them was typed in by a person.

Issue Register by Component

Illustrative rows for a fictional retailer, Wrenfield. An axe export of 4,812 findings across 340 pages, with every selector resolved to the component that rendered it.

ComponentRuleCriterionInstancesPagesFilesOwnerEffort
PriceTagcolor-contrast1.4.3 AA1,2843121Design Systems1 hour
IconButtonbutton-name4.1.2 A9683401Design Systems1 day
ProductCard imageimage-alt1.1.1 A7422182Catalog4 hours
FilterCheckboxlabel4.1.2 A611961Search2 hours
Breadcrumb separatorlink-name2.4.4 A3843401Design Systems30 min
Root layouthtml-has-lang3.1.1 A3403401Platform15 min
CarouselDotbutton-name4.1.2 A210421Marketing Site3 hours
NewsletterInputlabel4.1.2 A96961Growth1 hour
SocialLinklink-name2.4.4 A88881Marketing Site1 hour
SortDropdownselect-name4.1.2 A42421Search1 hour

Twelve components in total. The top six carry 4,329 of the 4,812 findings, ninety percent, for about two working days of work. And no page in this audit contains a component that no other page contains, which is exactly what the page-sorted view was hiding.

Priority by User Impact

Ordered by whether the barrier blocks a task. The by-count rank is shown beside it so the disagreement is visible rather than implied.

OrderComponentBy countBlocks a taskWorkaroundEffortWhy here
1FilterCheckbox4thYesNone2 hoursRemoves browsing by size, colour and price for anyone not using a mouse. Fourth by count, first by consequence, and it is two hours.
2IconButton2ndYesNone1 dayOne of these is the cart trigger. An unnamed button in a purchase path is a blocked task rather than a degraded one.
3SortDropdown10thYesNone1 hourLowest count of anything critical here and it still outranks contrast, because an unnamed sort control cannot be operated at all.
5ProductCard image3rdPartialPartial4 hoursThe card's link text already names the product, so this degrades the experience rather than removing the task.
7PriceTag1stNoYes1 hourBy far the most numerous finding in the audit and the least blocking: zoom, high-contrast mode and forced colours all recover it.
11CarouselDot7thPartialPartial3 hoursCritical by rule and low by consequence, because the same content also appears further down the home page.

The two orders barely agree. Ranked by instances, the first thing a team fixes is a grey price label that browser zoom already recovers. Ranked by consequence, the first thing is a two-hour change that gives keyboard and screen reader users the catalogue back.

Retest Tracking

A merge is not a fix. Findings close on a rescan of the live pages plus, where the criterion is not machine-decidable, a person testing the task.

ComponentPRBeforeAfterAutomatedManual checkManual resultClosed
PriceTag#48121,2840PassNot required, contrast is machine-checkable-Yes
IconButton#48159680PassVoiceOver on Safari, tab the header and cart on three page typesEvery button announces its purposeYes
Breadcrumb separator#48083840PassNVDA on Firefox, confirm the chevron left the tab orderTab order goes crumb to crumbYes
Root layout#48073400PassVoiceOver, confirm the correct voice loadsPassYes
ProductCard image#482374231IncompleteVoiceOver, confirm alt describes the product-No
FilterCheckbox#4826611-In progressNVDA and VoiceOver, filter the catalogue keyboard only-No
VERIFIED TOTAL-2,9760---2,976 of 4,812

ProductCard image is the row that earns this sheet. The pull request merged, the count fell from 742 to 31, and 31 is not zero: there is a second render path the change missed, and those 31 selectors point straight at it. On a merge-driven tracker that component is done.

What is in the pack

01

Issue Register by Component

Every finding regrouped by the component that rendered its selector. Each row carries the rule ids it fails, the WCAG criteria and levels, the instance count, the owning team, an effort estimate in hours, and the fix written as a change rather than a symptom.

02

Findings by Page

The import, kept exactly as the audit delivered it, so the register can be checked against the vendor's report line by line. It also carries the column that ends the page-versus-component argument: how many pages hold a component no other page holds.

03

Priority by User Impact

The remediation order, ranked by whether the barrier blocks a task, degrades one, or neither. The by-count rank sits in the next column, so anyone asking why the biggest number in the audit is seventh gets an answer instead of a defence.

04

Developer Guidance

One entry per component, written so a ticket can be picked up without opening the audit: the pattern, the change, the call sites a signature change breaks, the acceptance criterion, and the trap in the obvious fix.

05

Retest Tracking

Instances before and after, the rescan date, and for every criterion a scan cannot settle, the screen reader, the browser, the task path and the outcome. Findings close from this sheet and nowhere else.

06

Remediation Plan and Conformance Statement

The plan engineering leads schedule from, and a published statement built only from verified retests, with the outstanding barriers listed by date rather than omitted.

How it works

  1. 1

    Send the export

    An axe, WAVE, Lighthouse, Pa11y or Deque CSV or JSON, a vendor's PDF, or several of them covering different parts of the site on different dates.

  2. 2

    Selectors become components

    Every selector resolves to the component that rendered it, using the front-end repo where you have one and the repetition pattern where you do not.

  3. 3

    Order by consequence

    Blocking beats degrading beats cosmetic, and cheap beats expensive inside each. The instance ranking stays visible next to it rather than driving it.

  4. 4

    Close on retests

    A rescan of the live pages, plus a person on the task path for anything a scan cannot decide, and the closed count recomputes itself.

Frequently asked questions

Which audit tools does it read?

axe, WAVE, Lighthouse, Pa11y and Deque exports as CSV or JSON, plus vendor PDF reports with the findings in tables. Send several at once. Overlapping scans get counted once with both engines recorded, and scans from different dates or scopes stay labelled rather than being merged into one present tense.

How does it know which component a selector belongs to?

Point it at the front-end repo and class names, test ids and file structure make the mapping direct. Without the repo it works from the selector's structure and its repetition: anything appearing in the same structural position on 312 pages is a shared component, and you can name it afterwards.

Why not just start with the pages that have the most findings?

Because instance count measures how often a component renders, not how much it costs a user. Low contrast is the most detected issue on the web and browser zoom recovers it. An unlabelled filter has far fewer instances and removes the catalogue entirely from anyone browsing with a keyboard.

Is contrast really worth a whole component fix?

One token usually is. WCAG sets the AA floor for normal text at a contrast ratio of 4.5 to 1, and a single failing token on a price label reproduces across every product tile on the site. The register shows that as one file, one hour, and four figures of findings closed.

Does this cover the barriers a scanner cannot see?

It states them and schedules them. Automated engines are explicit about their reach: the axe rule set names exactly which checks run automatically and which need review. So the plan books the keyboard and screen reader passes on your real task paths, and the conformance statement says which claims rest on which.

What stops the same findings coming back next year?

A retested component has an expected instance count of zero, so any later scan finding instances is flagged as a regression rather than a new finding, which points at the commit that reintroduced it. The plan also ends with the design-system constraint that makes the pattern unwritable, which is the actual fix, and the design system register counts whether anyone adopted it.

Our audit has 200 findings, not four thousand. Still useful?

Yes, and it finishes in an afternoon. The collapse is smaller and the ordering matters more, because at that size the temptation is to fix everything in file order and ship the cosmetic work first. It also arrives with a conformance statement, which is usually the reason the audit was commissioned. Rank the result against everything else you owe with the prioritization pack.

Find out how few fixes are in your audit

Send the export in whatever shape it arrived. The first number back is not the finding count, it is how many components those findings resolve to.

Regroup my audit