An accessibility audit is invaluable. It identifies problems that might otherwise go unnoticed, provides a structured view of a product's accessibility, and gives a team a concrete starting point for remediation.
But an audit report is a starting point, not a remediation plan.
It's tempting to treat the findings as the job: work through the list, close each issue, ship. But a finding tells you what went wrong in the rendered experience. It doesn't necessarily tell you why it happened, where it should be fixed, or how to prevent it from happening again.
That's where accessibility remediation becomes software engineering.
A finding is a symptom, not a location
An audit tells you what is wrong with the output. It doesn't tell you where in the system to fix it.
If the same failure shows up on ten pages, fixing ten pages may address the reported instances without addressing the cause. The more useful question is where the failure is produced.
A shared component. A template. A design-system primitive. The content. A third-party script.
The right fix often changes structure, not just an attribute.
The problem isn't working through findings one by one. That's often necessary. The problem is treating each finding as an isolated task without asking what produced it and whether the fix will hold up.
Fix only the output, and the failure can return the next time that output is generated. Fix the thing that generates it, and the fix has a much better chance of surviving the next change.
Remediation carries technical debt too
There is always a faster path. A line of JavaScript that rewrites the DOM after render. A one-off ARIA patch. A duplicated component variant that's "accessible this time."
Each can close a finding. Each can also leave the codebase worse: a script maintaining server-rendered markup indefinitely, conflicting ARIA, or a fix that breaks when the markup underneath it changes.
None of these approaches are always wrong. Sometimes they are the right solution given the constraints of the system.
But they should be deliberate engineering decisions.
A remediation should leave the code in a better state, not simply move the problem somewhere harder to see.
Regression is part of the problem
A fix applied only to the output is vulnerable to regression when that output is regenerated. Reuse a component in a new context. Copy a template. Take an upstream update. Onboard a developer who copies the existing pattern without knowing it's broken.
A fix built into the system is more resilient. When correctness is built into the component, template, design system, or development process, it doesn't have to be re-decided every time the same pattern is used.
That's the difference between fixing an instance and fixing the system that produced it.
A fix that doesn't survive the next change was never really a fix.
This is engineering, not a separate track
I don't treat accessibility remediation as separate from software engineering.
The requirement comes from the Web Content Accessibility Guidelines (WCAG). The failure surfaces in an audit. Deciding how to fix it is an engineering problem.
It means understanding the architecture, the rendering model, the component boundaries, the dependencies, the upgrade path, the tests, and the people who maintain the code after you leave.
There isn't always a universally correct code change. There is a correct engineering approach for the system in front of you.
The same finding needs a different fix in a React design system than in a Liquid theme, and knowing which is the job.
Good remediation leaves the system better
The measure of good remediation isn't simply whether the reported issues are gone. It's whether the software is better equipped to remain accessible after the work is finished.
Can the next developer understand and maintain the fix? Does the component or design system make the accessible pattern the default path? Is the implementation resilient to platform and dependency updates? Can new features build on the same accessible foundation instead of recreating the problem?
This is what makes accessibility remediation software engineering.
You're not just changing markup until it passes a test. You're making decisions about architecture, abstractions, maintainability, dependencies, and how the software will evolve.
The audit identifies the problem. The remediation is the engineering work of solving it well.
Closing a finding is the easy part. Fixing the system that produced it is the work.
Top comments (2)
This bites hardest in generated documents. I build an HTML to PDF API with PDF/UA output, and there the tag tree is produced once at render time from whatever markup arrived. A DOM patch applied afterwards has nothing to attach to, because there is no output left to fix. If the heading levels are wrong in the template they are wrong in every PDF that template will ever produce, and the checker tells you the tag tree is broken without telling you which component wrote it.
Do you find teams accept the finding-is-a-symptom framing, or does the audit report still end up being the plan?
This is a sharper version of the point than I made in the post, and I might borrow it.
In a rendered DOM, you can at least hack the output, badly, with a script that patches nodes after the fact. In a generated PDF, there's nothing to patch. The tag tree is a build artifact, so if the template is wrong, the fix has nowhere to live except in the template. The constraint removes the shortcut entirely, which is oddly clarifying.
Your checker point is the "symptom, not a location" idea made concrete. The validator localizes the failure in the artifact, not in the source that produced it. Tracing "this tag tree is broken" back to "this component generated it" is the actual engineering work, and it's exactly the part the report can't do for you.
On whether teams accept the framing, honestly, the report still ends up being the plan more often than I'd like. Two things drive that: deadline pressure and who owns the fix. When the people closing findings don't maintain the system, there's little incentive to fix upstream, so they patch the instance and move on.
The framing tends to land when I can make the systemic cost concrete: "This regresses on the next release," or, in your case, "Every PDF this template generates is already broken." When the cost is visible and the shortcut is impossible, the conversation moves upstream on its own. Generated documents are almost a gift for that.