Tracking Accessibility Debt in Component Libraries
Permalink to "Tracking Accessibility Debt in Component Libraries"Every component library has accessibility debt: a grid whose column reordering is drag-only, a chart without keyboard navigation, a date picker whose month change is silent. The danger is not that debt exists but that it is invisible — scattered across tickets, known only to the people who found it, and rediscovered by each product team that adopts the component. A debt register makes it visible, prioritised and shrinking.
This guide belongs to accessibility governance for data products.
Spec reference
Permalink to "Spec reference"Debt entries map to WCAG success criteria, but prioritisation should consider user impact:
- Blocker — a task cannot be completed by some users (e.g. SC 2.1.1 failure on a primary action).
- Major — a task is possible but with significant difficulty or a workaround (e.g. SC 4.1.3 missing sort announcement).
- Minor — friction that does not prevent tasks (e.g. an extra tab stop).
WCAG levels (A, AA) indicate conformance impact; severity indicates user impact. Track both.
When to use — and when not to
Permalink to "When to use — and when not to"Keep a register as soon as a component library has more than one consumer. Review it every release with design system and product leads.
Do not let the register replace fixing: it is a planning tool, not a parking lot. Do not track debt only in a generic issue tracker without component and severity fields; reports become impossible.
The misapplication: a register sorted by WCAG level, so a Level A issue in an obscure prop outranks a Level AA issue that blocks screen reader users on every dashboard.
Annotated code example
Permalink to "Annotated code example"Store debt as data next to the components, so documentation and reports are generated:
# packages/grid/a11y-debt.yml
- id: GRID-014
title: Column reorder requires dragging
criteria: ["2.5.7", "2.1.1"]
severity: blocker
workaround: "Use Columns menu > Move left/right (since 5.1)"
affected: [billing, analytics, admin, crm, inventory, support]
status: in-progress
target: "5.3"
- id: GRID-021
title: Sort change not announced in virtualized mode
criteria: ["4.1.3"]
severity: major
workaround: null
affected: [analytics, support]
status: planned
target: "5.4"
// Generate a component conformance badge and a burn-down from the YAML files
const open = debts.filter(d => d.status !== 'fixed');
const byComponent = groupBy(open, d => d.component);
for (const [c, items] of Object.entries(byComponent))
writeBadge(c, items.some(i => i.severity === 'blocker') ? 'blockers' : items.length ? 'known issues' : 'no known issues');
writeBurndown(history.concat({ release: version, blocker: count(open, 'blocker'), major: count(open, 'major'), minor: count(open, 'minor') }));
Keyboard & AT behaviour
Permalink to "Keyboard & AT behaviour"Severity should be judged by testing with users’ tools, not by reading criteria:
| Observation | Severity | Reason |
|---|---|---|
| Keyboard user cannot reorder columns at all | Blocker | Task impossible |
| Screen reader user cannot tell sort changed | Major | Task possible after exploring |
| Extra tab stop in toolbar | Minor | Friction only |
| Focus ring 2.8:1 in dark mode | Major | Low-vision users lose place |
| Chart missing table view | Blocker for data tasks | Information unavailable |
Integration context
Permalink to "Integration context"New debt is often found through accessibility regression triage for data UIs and audits (manual accessibility audits). The register feeds the remarks in VPAT and ACR for data-heavy products. Component conformance status belongs with versioning and deprecating inaccessible component APIs.
Gotchas
Permalink to "Gotchas"Product-level debt. Some debt lives in how products use components (missing labels, wrong props). Track it in the product, linked to the component guidance it violates.
Closing without verification. Mark entries fixed only after testing with the relevant assistive technology, not when the pull request merges.
Workaround rot. Workarounds documented in the register must be tested too; they break as often as anything else.
Common mistakes
Permalink to "Common mistakes"- Prioritising by WCAG level instead of user impact.
- Debt spread across trackers with no component field.
- No workaround recorded.
- Never reporting debt to leadership.
Framework notes
Permalink to "Framework notes"Monorepo design systems can keep a11y-debt.yml per package and generate documentation with Storybook (a “Known accessibility issues” docs block) or a docs site. Issue trackers (Jira, GitHub Issues, Linear) can hold the same data if they have component, severity and WCAG fields; generate the burn-down from their APIs.
Worked example
Permalink to "Worked example"A design system team supporting 15 products found the same grid issues filed 40 times across product trackers. They created a register with 23 deduplicated entries, rated by user impact, each linked to affected products and a workaround. Component docs gained a “Known accessibility issues” section generated from the register. Leadership got a one-page burn-down per release. Within four releases, blockers went from three to zero, and product teams stopped filing duplicates because they could see the status.
Reporting to leadership
Permalink to "Reporting to leadership"Leadership needs three numbers per release, not the register itself: open blockers, open majors, and the trend since the previous release. Add one sentence on the most important change (“Drag-only column reordering resolved for all six products”) and one on the biggest remaining risk. A single chart of the burn-down, released on the same cadence as product metrics, keeps accessibility in the same conversation as performance and reliability.
Testing checklist
Permalink to "Testing checklist"Design system notes
Permalink to "Design system notes"Treat the register as part of the design system’s public surface: consumers deserve to know what is broken and when it will be fixed. It also turns accessibility from an occasional audit topic into a measurable product metric.
FAQ
Permalink to "FAQ"How is accessibility debt different from bugs?
Debt includes known gaps by design (features never built accessibly) as well as bugs. Both belong in the register.
Who owns the register?
The design system team for component debt; product teams for product-level debt, with links between them.
Should the register be public?
Internally public at least. Some companies publish component conformance externally; it builds trust with customers.
How do we rate severity consistently?
Use user-impact definitions with examples, and calibrate by rating a few issues together as a team.
How often should it be reviewed?
Every release, with a quick triage of new entries weekly.
Can debt be "accepted"?
Occasionally, with a documented reason and workaround, reviewed periodically. Accepted debt still appears in ACR remarks.
What fields does a debt entry need at minimum?
An ID, title, component, WCAG criteria, severity, workaround, affected products, status and target release. Anything less makes prioritisation and reporting guesswork.
Related
Permalink to "Related"- Regression triage — where new debt is found
- VPAT and ACR — reporting debt to customers
- Versioning and deprecating inaccessible APIs — retiring debt-causing APIs