How to Find Accessibility Issues While You Code
Catch accessibility issues as you build with source linting, browser checks, and hands-on review. Learn what each method can find and how to fit it into your workflow.
Find accessibility issues while you code by combining checks at three levels: lint source code as you edit, evaluate the rendered page in a browser or CI, and manually use the interface with a keyboard and assistive technology. Each method sees different problems. Automated findings help locate candidates, but they cannot establish that an experience is accessible by themselves.
A practical loop is: lint → render and scan → manually evaluate → fix → rerun. Start with the component or page you are changing, then check broader flows when a change affects shared patterns or navigation.
1. Catch source-level issues as you edit
For React and JSX projects, eslint-plugin-jsx-a11y statically evaluates JSX patterns and can flag some likely accessibility problems. It is useful as an early warning in the editor and in the project’s lint command.
Install it using the package manager already used by your project:
npm install --save-dev eslint-plugin-jsx-a11y
For a legacy ESLint configuration using .eslintrc, enable the recommended rules:
{
"extends": ["plugin:jsx-a11y/recommended"]
}
For ESLint’s flat configuration, a basic setup can import the plugin and its recommended config. Check the plugin documentation for the configuration format and version used by your project:
import jsxA11y from "eslint-plugin-jsx-a11y";
export default [
jsxA11y.flatConfigs.recommended,
{
files: ["**/*.{jsx,tsx}"],
},
];
Run the project’s lint command, or invoke ESLint for the files you changed:
npx eslint src/
Use the linter to catch source patterns such as images without text alternatives or controls without an accessible name. A clean lint result does not mean the rendered interface is correct: the plugin maintainers note that it does not evaluate final rendered HTML. Dynamic content, component composition, and context-dependent meaning require other checks.
2. Check the rendered page or component
Source linting examines code; browser evaluation examines what the user-facing page actually renders. W3C/WAI lists the axe DevTools Extension for in-browser evaluation and axe DevTools Linter for supported source files in IDE and CI/CD workflows. Confirm current language and framework support in the W3C/WAI directory before choosing a tool.
Use a browser evaluation tool after rendering the changed state. Scan the page or component state that matters, then inspect each finding in context. A scanner can identify candidate issues, but it cannot decide whether the information is clear, whether a control’s behavior makes sense, or whether the whole task is usable.
For projects that use Lighthouse Audits or axe-core in their existing development process, include those checks where they fit the build and review path. Digital.gov recommends integrating automated checks during development and names axe-core, jsx-a11y, Lighthouse Audits, and AccessLint as examples. Treat results as a way to find and fix issues early, not as proof of accessibility.
3. Put checks in the normal development workflow
- While editing: run source linting on changed files and fix actionable findings near the code that introduced them.
- In local review: render the changed page and relevant interaction states, then run browser evaluation.
- In CI: keep automated checks in the project’s existing lint, test, or review path so regressions can be caught before release. Choose checks the project can run reliably and maintain.
- At review: ask someone to evaluate the affected task with a keyboard and, where appropriate, assistive technology.
- After a fix: rerun the relevant automated checks and revisit the interaction in its rendered context.
Choose tools based on where they run (source editor, browser, or CI), what they inspect (code, one rendered page, or a broader site), how automated the evaluation is, and which project files they support. W3C/WAI notes that tools vary in scope and can support automated, manual, or simulated evaluation.
4. Manually evaluate behavior and meaning
Manual review fills gaps that a rule-based scan cannot resolve. For the changed task, try the interface without a mouse and check that focus is visible, moves in a sensible order, and reaches the controls needed to complete the task. Verify that controls communicate their purpose and current state, errors are understandable, and dynamic changes are perceivable.
Use assistive technology where the task or change calls for it. The eslint-plugin-jsx-a11y maintainers explicitly recommend treating automated tools as one part of a larger testing process and testing applications with assistive technology. W3C also recognizes automated, semi-automated, and manual testing as evaluation approaches.
Manual testing is not a single pass that certifies a site. It is a way to evaluate real tasks and context that automated rules may not understand. For a shared component, check representative uses and states, not only its isolated default state.
5. Turn a finding into a verified fix
- Reproduce it: identify the page, state, and user action where the issue occurs.
- Inspect the context: decide whether the finding is a real problem, a false positive, or a symptom of a broader interaction issue.
- Fix the cause: make the smallest change that corrects the accessible name, semantics, focus behavior, content, or interaction.
- Check the rendered result: repeat the action and confirm the change works in the browser.
- Rerun relevant checks: use the linter or browser evaluation again, then manually revisit the affected task.
This repeat-and-review sequence is a practical workflow recommendation: tool findings locate candidates, while the developer evaluates the interface and user task.
Choosing a check for the work
| Where | Example | Useful for | Limit |
|---|---|---|---|
| Source editing | eslint-plugin-jsx-a11y |
Static evaluation of JSX patterns during development. | Does not evaluate final rendered output by itself. |
| IDE or CI | axe DevTools Linter | Code checks for supported files in development and delivery workflows. | Confirm current file and framework support and product terms. |
| Browser | axe DevTools Extension | Evaluation of a rendered page or state. | A browser scan is one part of evaluation, not a guarantee. |
| Broader evaluation | W3C/WAI tool-selection guidance and ACT resources | Matching evaluation scope and method to the project. | Tool choice depends on whether you need page or site coverage and automated, manual, or simulated testing. |
Primary references: W3C/WAI evaluation tools, eslint-plugin-jsx-a11y documentation, Digital.gov accessibility guidance for teams, and W3C/WAI ACT overview.
Or skip the browser setup
For a screenshot of a rendered page during visual review, ScreenshotNeo provides a website screenshot API and MCP server. It complements accessibility evaluation; a screenshot does not replace linting, browser accessibility checks, keyboard review, or assistive-technology testing.
One GET request captures a page. See the ScreenshotNeo API documentation for options and setup.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000.
Sign up for 1,000 free screenshots a month, with no card.
Troubleshooting
| Symptom | Likely cause | What to do |
|---|---|---|
| The JSX linter reports no issues, but the page still has a defect. | Static rules do not inspect the final rendered page or every contextual problem. | Evaluate the rendered state, then manually check the affected task and assistive-technology behavior as appropriate. |
| A browser scanner reports a possible issue you cannot reproduce. | The finding may depend on page state, timing, or context, or may need human review. | Reproduce the same state, inspect the element and user task, and determine whether the result is a true issue or needs a documented disposition. |
| A tool does not scan a file or framework. | That tool may not support the project’s current file type or framework. | Check its current support list and select a check that covers the rendered page or supported source format. |
| Automated checks pass, but keyboard use is confusing. | The issue involves behavior, focus order, or task context that a rule may not judge. | Walk through the task with the keyboard, inspect focus and state changes, and test with assistive technology when relevant. |
| A defect reappears after a fix. | The underlying shared component or another state may still contain the problem. | Check other uses and states of the component, then add the relevant check to the project’s regular review path. |
Performance, reliability, and cost
Source linting is suited to frequent use while editing because it can run on the code under change. Browser and CI checks add coverage of rendered output, but their usefulness depends on scanning the right page states and keeping the workflow maintainable. Manual evaluation takes focused reviewer time and should target the interaction and context affected by the change.
Keep checks close to the work they can meaningfully evaluate. A source rule can provide quick feedback about a code pattern; a browser evaluation can inspect a rendered page; a person can judge whether a task makes sense. No single layer replaces the others, and a passing automated result is not a conformance guarantee. The cited research does not establish a universal detection-rate percentage or a fixed cost comparison, so choose the workflow based on project scope and the effort needed to review its actual user tasks.
FAQ
Can automated accessibility checks prove my app is accessible?
No. They can catch errors, but they cannot guarantee accessibility. Combine them with manual evaluation of the affected experience.
Should I test a component or a whole page?
Test at the scope of the change. Check a component in its rendered context, and evaluate the page or broader flow when shared behavior or navigation is affected.
When should I use assistive technology?
Include it when the changed task, component, or interaction needs evaluation beyond source and browser automation. The JSX linter maintainers recommend testing applications with assistive technology as part of a larger process.
What should I do with a false positive?
Reproduce the relevant state and inspect the issue in context. If it is not a defect, record the reasoning in the project’s review process and continue checking the user task manually.


