Back to Blog
How I Use AI to Audit and Fix WCAG 2.2 Compliance Issues (An Australian Developer's Workflow)
Photo by Rodion Kutsaiev on Unsplash

Most teams treat accessibility as a final-pass concern — something you bolt on before launch if there's time. There usually isn't. What actually happens is that you ship a site that fails WCAG in a dozen quiet, costly ways, and you find out about it when a complaint lands with the Australian Human Rights Commission or a client fails a government accessibility audit.

AI doesn't solve the mindset problem. But it does obliterate the excuse that fixing accessibility takes too long.

This post walks through a workflow for auditing and remediating WCAG 2.2 AA violations using AI tooling — covering the three highest-impact problem areas: alt text, colour contrast, and keyboard navigation. The legal framing is Australian-first (DDA + AHRC), but the technical approach applies globally.


The legal context: DDA, WCAG, and why AU devs need to care

In Australia, web accessibility obligations sit under the Disability Discrimination Act 1992 (DDA). The DDA prohibits discrimination against people with disability in accessing goods, services, and information — which courts and the AHRC have consistently applied to websites and digital products.

The Australian Human Rights Commission published an Advisory Note confirming that inaccessible websites can constitute unlawful discrimination under the DDA. Australian government agencies are additionally bound to WCAG 2.1 AA under the Digital Service Standard (managed by the Digital Transformation Agency). For non-government work, WCAG 2.2 AA is the current best-practice target.

Unlike the US — where the Americans with Disabilities Act (ADA) and Section 508 are enforced through federal and state civil litigation — Australian complaints typically go through AHRC conciliation first. That makes the process less immediately adversarial, but it is not a reason to ignore compliance. AHRC complaints are public, they damage client relationships, and courts can and do hand down enforceable orders.

WCAG 2.2 adds nine new success criteria on top of 2.1, mostly around cognitive and motor accessibility: larger touch targets (2.5.8), consistent help mechanisms (3.2.6), and removing authentication challenges that require cognitive tests (3.3.7 and 3.3.8). The criteria you're most likely to fail are still the 2.0 and 2.1 originals — alt text, contrast, keyboard traps — but 2.2 is now the bar worth targeting.


Step 1 — Run the automated audit and pipe it through AI

Automated tooling catches roughly 30–40% of WCAG violations. That number is a ceiling, not a ceiling to aspire to. The remaining issues — keyboard flow, meaningful alt text, logical heading order — require human or AI-assisted review. Start with automation to clear the noise, then go deeper.

Install axe-core CLI:

yarn add --dev @axe-core/cli

Run it against a local or staging URL:

yarn axe http://localhost:3000 --save axe-report.json

The raw JSON output is noisy and unhappy reading. Feed it to an AI instead:

I have an axe-core accessibility audit report for a Next.js site. Here is the raw JSON:

[paste report]

Please:
1. Group violations by WCAG 2.2 success criterion (e.g. 1.1.1, 1.4.3)
2. Sort each group by number of affected elements (most impactful first)
3. For each group, write one concrete fix — not a generic suggestion, but the actual code change or pattern
4. Flag any violations that require human judgement (e.g. meaningful vs decorative image decisions)
5. Estimate fix time per group (quick win vs substantial refactor)

This turns a 400-line JSON wall into a prioritised remediation queue in under a minute. The fix recommendations are usually 80% usable without modification — the remaining 20% need context you hold about the specific component.

For Next.js App Router projects, you can also run axe-core directly in a Playwright test:

// tests/accessibility.spec.ts
import { test, expect } from '@playwright/test';
import AxeBuilder from '@axe-core/playwright';

test('homepage meets WCAG 2.2 AA', async ({ page }) => {
  await page.goto('/');

  const results = await new AxeBuilder({ page })
    .withTags(['wcag2a', 'wcag2aa', 'wcag22aa'])
    .analyze();

  expect(results.violations).toEqual([]);
});

Run it with:

yarn playwright test tests/accessibility.spec.ts

Any violation fails the test. The output names the element, the rule, and the severity. Combined with the AI triage step above, you have an actionable queue before you've written a single fix.


Step 2 — Alt text at scale (WCAG 1.1.1)

Alt text is the most common WCAG failure and the most tedious to fix manually at scale. AI handles it well — with a critical caveat: AI-generated alt text still needs intent-aware review. A decorative image should have alt="". A product image needs to describe what a sighted user would infer from it, not just what's in the frame.

A workflow for Next.js projects:

// scripts/generate-alt-text.ts
import Anthropic from '@anthropic-ai/sdk';
import fs from 'fs';
import path from 'path';

const client = new Anthropic();

async function generateAltText(imagePath: string): Promise<string> {
  const imageBuffer = fs.readFileSync(imagePath);
  const base64Image = imageBuffer.toString('base64');
  const ext = path.extname(imagePath).slice(1).toLowerCase();
  const mediaType = ext === 'jpg' ? 'image/jpeg' : `image/${ext}`;

  const response = await client.messages.create({
    model: 'claude-opus-4-6',
    max_tokens: 150,
    messages: [
      {
        role: 'user',
        content: [
          {
            type: 'image',
            source: { type: 'base64', media_type: mediaType, data: base64Image },
          },
          {
            type: 'text',
            text: `Write alt text for this image following WCAG 1.1.1 guidelines.
Rules:
- If decorative (purely visual, no informational value): respond with exactly: DECORATIVE
- Otherwise: write a concise description (under 100 characters) of what a screen reader user needs to understand
- Don't start with "Image of" or "Photo of"
- Focus on the informational content, not the aesthetic`,
          },
        ],
      },
    ],
  });

  const text = response.content[0].type === 'text' ? response.content[0].text.trim() : '';
  return text === 'DECORATIVE' ? '' : text;
}

You don't have to run this over every image on every deploy. Run it once as a migration script across existing content, write the results to a JSON manifest, then reference the manifest in your <Image> component.

For new content, the better long-term pattern is to enforce alt text at the data layer — requiring it in your CMS schema — and use the AI generation as a fallback only.


Step 3 — Colour contrast (WCAG 1.4.3 and 1.4.11)

WCAG 1.4.3 requires a contrast ratio of 4.5:1 for normal text and 3:1 for large text (18pt/14pt bold and above). WCAG 1.4.11 extends the 3:1 requirement to non-text UI components — buttons, input borders, icons.

Most contrast failures happen in two places: muted text on light backgrounds (e.g. #999 on white is 2.85:1 — a fail), and brand-coloured interactive elements where the design team didn't check against the actual WCAG ratio.

Axe-core will catch most of these. The fix is mechanical — adjust the hex value until you hit the threshold. The problem is that designers often push back because the "correct" value kills the brand feel.

This is where AI earns its keep. Prompt:

My brand's primary button colour is #0057FF on a white (#FFFFFF) background.
The current contrast ratio is 4.82:1, which passes WCAG AA for large text
but I need it to pass for normal text (4.5:1 minimum).

Wait — that already passes. Let me give you a real failure:

My link colour is #5A9BD4 on white. The contrast ratio is 3.4:1 — a WCAG AA fail.
Please suggest 3 alternative hex values that:
1. Pass WCAG 2.2 AA (4.5:1 minimum)
2. Stay within the same blue hue family (hue 210–220)
3. Are ranked from closest-to-original to furthest

This gets you usable options in seconds rather than spinning a contrast checker manually. Build the most-used colour pairs into your design token validation so the check runs automatically:

// scripts/validate-contrast.ts
import { colord } from 'colord';
import a11yPlugin from 'colord/plugins/a11y';

colord.extend([a11yPlugin]);

const tokenPairs: Array<{ fg: string; bg: string; label: string; level: 'AA' | 'AAA' }> = [
  { fg: '#111827', bg: '#FFFFFF', label: 'body-text/page-bg', level: 'AA' },
  { fg: '#6B7280', bg: '#FFFFFF', label: 'muted-text/page-bg', level: 'AA' },
  { fg: '#FFFFFF', bg: '#0057FF', label: 'button-label/primary-bg', level: 'AA' },
];

let failed = false;

for (const pair of tokenPairs) {
  const ratio = colord(pair.fg).contrast(pair.bg);
  const required = pair.level === 'AAA' ? 7 : 4.5;
  const pass = ratio >= required;

  if (!pass) {
    console.error(`FAIL [${pair.label}] ratio: ${ratio.toFixed(2)} (required ${required})`);
    failed = true;
  } else {
    console.log(`PASS [${pair.label}] ratio: ${ratio.toFixed(2)}`);
  }
}

if (failed) process.exit(1);

Add this to your pre-commit hook or CI pipeline. Contrast regressions become impossible to ship silently.


Step 4 — Keyboard navigation and ARIA (WCAG 2.1.1, 2.4.3, 4.1.2)

This is the one that automation can't fully solve — and the one that trips up the most senior engineers who "know about accessibility" in theory.

The three most common keyboard navigation failures in React/Next.js:

1. Interactive elements that aren't natively focusable. If you've built a click handler on a div or span, it's invisible to keyboard users. Use a button or a element unless you have a specific reason not to — and if you do have a reason, add tabIndex={0}, role, and keyboard event handlers.

2. Focus traps and focus loss. When a modal opens, focus should move into it. When it closes, focus should return to the trigger. This sounds simple. Most custom modal implementations get it wrong in at least one direction.

3. Missing or incorrect ARIA labels. Icon-only buttons, custom dropdowns, and tab panels almost always need explicit ARIA attributes that axe-core won't catch because the structure is technically valid.

AI helps here as a code reviewer. Paste a component and use this prompt:

Review this React component for WCAG 2.2 keyboard accessibility issues.
Check specifically:
- Is every interactive element reachable by Tab key?
- Are focus states visible (not outline: none without replacement)?
- Does any custom interactive element need role, aria-label, or aria-expanded?
- Are there any click handlers on non-interactive elements?
- If this is a modal/dialog, does it manage focus correctly on open and close?

[paste component code]

Here is a before/after on a common pattern — an icon button:

// Before — fails WCAG 4.1.2 (no accessible name) and 2.1.1 (no keyboard handler)
<div onClick={handleClose}>
  <XIcon />
</div>

// After — WCAG compliant
<button
  type="button"
  onClick={handleClose}
  onKeyDown={(e) => e.key === 'Enter' && handleClose()}
  aria-label="Close dialog"
  className="focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-blue-500"
>
  <XIcon aria-hidden="true" />
</button>

Note aria-hidden="true" on the icon — screen readers don't need to announce it because the aria-label on the button covers it. Without this, some screen readers will read both the label and the icon's accessible name.

For skip links — required under WCAG 2.4.1 — add this as the very first element inside body in your Next.js root layout:

// src/app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <a
          href="#main-content"
          className="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-white focus:text-black focus:rounded focus:shadow-lg"
        >
          Skip to main content
        </a>
        <main id="main-content">
          {children}
        </main>
      </body>
    </html>
  );
}

Step 5 — Baking it into CI/CD

Individual fixes are fine. A CI gate that prevents regressions from ever reaching staging is better.

Here is a minimal GitHub Actions workflow:

# .github/workflows/accessibility.yml
name: Accessibility Audit

on:
  pull_request:
    branches: [main, staging]

jobs:
  a11y:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: yarn install --frozen-lockfile

      - name: Build
        run: yarn build

      - name: Start server
        run: yarn start &
        env:
          PORT: 3000

      - name: Wait for server
        run: npx wait-on http://localhost:3000

      - name: Run contrast token validation
        run: yarn ts-node scripts/validate-contrast.ts

      - name: Run Playwright accessibility tests
        run: yarn playwright test tests/accessibility.spec.ts

      - name: Run axe-core CLI scan
        run: yarn axe http://localhost:3000 --tags wcag2a,wcag2aa,wcag22aa

This won't replace a full WCAG audit before a major launch — but it will stop the easy regressions: someone deletes alt text, adds an unlabelled icon button, or introduces a contrast-failing colour. Those fixes cost nothing to prevent and are genuinely embarrassing to ship.


What AI can't do here

Worth being direct about the limits. AI-assisted accessibility work is fast and genuinely useful, but it has a hard ceiling.

Automated tooling — including AI-reviewed code — cannot reliably assess: whether alt text is meaningful in context, whether a complex data visualisation has an accessible text alternative, whether the reading order of a page makes sense to a screen reader user, or whether a cognitive accessibility pattern (like consistent navigation) is actually being followed across the site.

The only way to catch those is to have a user with a disability test your product. That's not a platitude — it's the test that axe-core, Claude, and every contrast checker in existence will fail to replicate. If you're building anything beyond a personal project, budget for it.


Key Takeaways

  • In Australia, web accessibility obligations fall under the DDA (1992), enforced by the AHRC — not the US ADA. Government sites must meet WCAG 2.1 AA; WCAG 2.2 AA is the current best-practice target for everyone.
  • Use axe-core + AI triage to convert a raw violation report into a prioritised, costed fix queue in under five minutes.
  • Alt text generation can be scripted with AI, but the decorative-vs-informative decision still needs human judgement per image.
  • Contrast failures are mechanical to fix — add a token validation script and make it a CI gate so they can't regress.
  • Keyboard navigation and ARIA are the hardest to automate — use AI as a code reviewer on individual components, not as a replacement for testing with real assistive technology.
  • A GitHub Actions a11y workflow takes a few hours to set up and prevents the category of regressions that would otherwise reach production silently.

Sources & References

  1. Australian Human Rights Commission. "World Wide Web Access: Disability Discrimination Act Advisory Notes". AHRC. 2014.
  2. Digital Transformation Agency. "Digital Service Standard — Criterion 9: Make it accessible". Australian Government. 2023.
  3. W3C Web Accessibility Initiative. "Web Content Accessibility Guidelines (WCAG) 2.2". W3C. 2023.
  4. Deque Systems. "axe-core: Accessibility Engine for Automated Web UI Testing". 2024.
  5. W3C WAI. "Understanding WCAG 2.2 — New Success Criteria". W3C. 2023.
  6. Australian Human Rights Commission. "Disability Rights — Web Accessibility". AHRC. 2024.
Older Post

AI as Your Frontend Debugger: From Cryptic Error to Fix in Under 5 Minutes

Suggested Reading

Architectural Note:This platform serves as a live research laboratory exploring the future of Agentic Web Engineering. While the technical architecture, topic curation, and professional history are directed and verified by Maas Mirzaa, the technical research, drafting, and code execution for this post were augmented by Claude (Anthropic). This synthesis demonstrates a high-velocity workflow where human architectural vision is multiplied by AI-powered execution.