Accessibility bug reports that hold up to review
You file a ticket that says "checkout is not accessible for screen readers". Two weeks later a developer closes it: "works on my machine, VoiceOver reads the page fine."
Both of you are right. You tested a different button, with a different screen reader, on a different browser. The ticket never said which.
An accessibility bug report survives review when it names the rule that was broken, the tools you used, and the person who is now stuck.
Short version
- Cite the exact WCAG success criterion: number, name, and level.
- Record the assistive technology by name and version, plus browser and operating system.
- Write what the user heard or could not do, not what the code looks like.
- Set severity by whether the task can still be finished.
- Use automated tool output as evidence, never as the whole report.
What WCAG and a success criterion actually mean
WCAG stands for Web Content Accessibility Guidelines. It is the international standard for making websites usable by people with disabilities. Most teams work to WCAG 2.1 or WCAG 2.2.
A success criterion is one testable rule inside that standard. Each one has a number, a short name, and a conformance level: A, AA, or AAA. Level A is the minimum. Level AA is what most laws and contracts require. Level AAA is extra.
You write a criterion like this:
WCAG 2.2 SC 1.4.3 Contrast (Minimum), Level AA
"SC" just means success criterion. Include all four parts. The number lets a developer find the rule. The name explains it without clicking. The level tells the product manager whether this blocks a compliance deadline.
Here are three you will use constantly:
- SC 1.4.3 Contrast (Minimum), Level AA — text must have enough contrast against its background.
- SC 2.4.7 Focus Visible, Level AA — when you tab to an element, you must be able to see where you are.
- SC 4.1.2 Name, Role, Value, Level A — every control must tell assistive technology what it is called and what it does.
If you are not sure which criterion applies, say so in the ticket. A guess marked as a guess is better than silence.
Record the assistive technology you used
Assistive technology is software or hardware that helps someone use a computer. A screen reader is the most common example: it reads the page out loud.
Screen readers behave differently. The same page can work in one and fail in another, so a report without the tool name is not reproducible.
Write the full stack:
NVDA 2025.1 with Firefox 128 on Windows 11
VoiceOver with Safari 18 on macOS 15
That is three things: screen reader and version, browser and version, operating system. Add the browse mode if it matters, for example "NVDA in focus mode".
If you tested with the keyboard only and no screen reader, say that too. Keyboard-only testing means you unplug the mouse and use Tab, Shift+Tab, Enter, Space, and the arrow keys. Many real bugs show up there first.
Write what the user heard, not what the code says
This is the part most reports get wrong. Do not write "the button is missing aria-label". That is a fix, and it may not be the right fix.
Write what happened in the ear or on the screen.
Bad: Icon button needs an accessible name.
Good: NVDA announces the cart icon button as "button" with no name. There is no way to know it opens the cart.
The second version proves the bug exists for a user. The first is an opinion about the code, and developers can argue with opinions. Nobody argues with a recording of what NVDA said.
For keyboard bugs, describe the movement:
Good: Pressing Tab from the email field skips the "Apply promo code" button and lands on "Place order". The promo button cannot be reached by keyboard at all.
Frame the user impact
Two questions answer this: who is blocked, and is there a workaround.
Write one sentence for each.
Who is blocked: screen reader users cannot identify the cart button, so they cannot review their order before paying.
Workaround: none. The button has no visible text label to read either.
A workaround changes everything. "The user can complete the same task from the account menu" turns a blocker into a major bug. "There is no other path" keeps it a blocker. State it explicitly so nobody has to guess.
Set severity by task completion
Use one simple test: can the user finish the task?
| Severity | Test | Example |
|---|---|---|
| Blocker | The task cannot be completed at all with this technology | Pay button is unreachable by keyboard |
| Major | The task can be completed, but only with real effort or guessing | Icon button announced as "button" with no name |
| Minor | The task completes normally, but the experience is worse | Focus outline is faint but visible |
Do not set severity by how easy the fix looks. A one-line fix for a blocker is still a blocker. Do not set it by how many users are affected either. Accessibility bugs often hit a small number of people completely, which is worse than hitting everyone slightly.
Use automated tools as evidence, not as the report
Tools like axe DevTools and Lighthouse scan a page and report violations. They are fast and worth running on every build.
They also find only part of the problem. Automated scans catch roughly a third of accessibility issues. They can measure a contrast ratio. They cannot tell you that the focus order jumps backwards, that a label reads "Field 1", or that an error message is announced before the user reaches the field.
When a tool does flag something, include its rule ID. Rule IDs like color-contrast and button-name are stable strings that developers can search in their code and in the axe documentation.
Good: axe DevTools rule
color-contrastfails on the order summary text. Measured 3.1:1 against the 4.5:1 required by SC 1.4.3.
Then add the manual detail the tool could not give you: which text, on which page, at which zoom level, and what a user actually loses.
Weak lines, and how to fix them
| Weak line | Criterion to cite | Strong version |
|---|---|---|
| Text is hard to read | SC 1.4.3 Contrast (Minimum), Level AA | Order summary text #9CA3AF on #FFFFFF measures 3.1:1, below the required 4.5:1 |
| Can't tell where I am when tabbing | SC 2.4.7 Focus Visible, Level AA | No focus outline appears on the "Place order" button when reached by Tab in Chrome 130 |
| Screen reader says nothing useful | SC 4.1.2 Name, Role, Value, Level A | NVDA 2025.1 announces the cart icon button as "button" with no name |
| Form is confusing | SC 3.3.2 Labels or Instructions, Level A | The card expiry field has no label; VoiceOver announces it as "edit text" only |
| Image not described | SC 1.1.1 Non-text Content, Level A | The product thumbnail has empty alt text, so NVDA skips it and the item cannot be identified |
| Error not announced | SC 4.1.3 Status Messages, Level AA | "Card declined" appears visually but is not announced by NVDA after submit |
A copy-paste accessibility bug report template
Title: Cart icon button announced as "button" with no name on checkout
WCAG criterion: WCAG 2.2 SC 4.1.2 Name, Role, Value, Level A
Tool rule ID: axe DevTools `button-name`
Environment
- URL: https://staging.example.com/checkout
- Screen reader: NVDA 2025.1
- Browser: Firefox 128
- OS: Windows 11
- Test account: [email protected]
- Build: 4.7.2
Steps to reproduce
1. Start NVDA and open https://staging.example.com/checkout in Firefox 128.
2. Sign in as [email protected].
3. Press Tab until focus reaches the header row.
4. Press Tab once more to reach the cart icon in the top right.
5. Listen to the announcement.
Expected
NVDA announces something like "Cart, 3 items, button".
Actual
NVDA announces only "button". No name, no item count.
User impact
Who is blocked: screen reader users cannot find or identify the cart,
so they cannot review the order before paying.
Workaround: none. The button has no visible text either.
Severity: Blocker (the purchase review step cannot be completed)
Evidence
- Screen recording with NVDA speech viewer: [link]
- axe DevTools export: [link]
Copy that block into your tracker and replace the values. The headings matter more than the wording. A reviewer should find "WCAG criterion", "Environment", and "Severity" without reading a paragraph.
For the evidence section, capture the environment while you are still on the page. Browser-based tools such as Crosscheck record the screenshot, console logs, network requests, and browser details at the moment you report, so the environment block fills itself in and you only write the accessibility detail by hand.
A short checklist before you file
- Does the ticket name a WCAG criterion with number, name, and level?
- Does it name the screen reader, browser, and operating system with versions?
- Do the steps start from a URL and use real keys, not "navigate to the button"?
- Does it say what the user heard or could not do?
- Does it answer who is blocked and whether a workaround exists?
- Is the severity tied to task completion?
Six yeses and the ticket will survive review.
Frequently asked questions
Do I have to know WCAG by heart to file a good bug? No. Learn the six or seven criteria that cover most issues, and mark anything else as a guess. A report with a wrong criterion but clear steps is still useful.
What if axe DevTools finds nothing but the page still feels wrong? File it anyway. Automated tools miss most focus order, labelling, and announcement problems. Describe what you experienced and skip the rule ID.
Which screen reader should I test with? Test with what your users use. NVDA with Firefox or Chrome on Windows covers the largest group. VoiceOver with Safari covers macOS and iOS.
Should severity be higher for accessibility bugs? Not automatically. Use the same task-completion test you use for other bugs. It usually pushes accessibility blockers up on its own.
What if the developer says it works for them? Ask which screen reader, browser, and version they used. Most disagreements are two different setups, and the version numbers in your report settle it in one message.




