Chrome Extension Accessibility Testing — Developer Guide

6 min read

Accessibility Testing for Chrome Extensions

Overview

Accessibility testing ensures extension UIs work for all users, including those using assistive technologies. Chrome extensions present unique testing challenges due to popup windows, content script injections, and isolated contexts.

Testing Tools

Chrome DevTools Lighthouse Audit

Run Lighthouse accessibility audits directly on extension pages:

  1. Open extension popup or options page
  2. DevTools > Lighthouse tab
  3. Select “Accessibility” category
  4. Run audit to get WCAG compliance score

axe-core Integration

Add axe-core to automated tests for continuous a11y validation:

import axe from 'axe-core';

async function runAccessibilityTest() {
  const results = await axe.run(document);
  if (results.violations.length > 0) {
    console.error('Accessibility violations:', results.violations);
  }
}

WAVE Extension

Web Accessibility Evaluation tool identifies:

Keyboard Navigation

Verify all interactions work without a mouse:

Focus Management

Test focus behavior:

Screen Reader Compatibility

Test with ChromeVox, NVDA, and VoiceOver:

Color Contrast Testing

Check contrast ratios using DevTools:

  1. Elements panel > computed styles
  2. Look for color and background-color
  3. Use color picker to verify 4.5:1 for normal text (3:1 for large text)

High Contrast Mode

Test with @media (forced-colors: active):

Content Script Testing

Injected UI Accessibility

Content scripts inject UI into host pages—test that you don’t break page accessibility:

Host Page Compatibility

Screen Reader Testing

ChromeVox (ChromeOS)

NVDA (Windows)

VoiceOver (macOS)

Keyboard-Only Navigation

Ensure every action works without a mouse:

Focus Trapping in Modals

Extension modals and overlays must trap focus:

function trapFocus(container) {
  const focusable = container.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const firstFocusable = focusable[0];
  const lastFocusable = focusable[focusable.length - 1];

  container.addEventListener('keydown', (e) => {
    if (e.key === 'Tab') {
      if (e.shiftKey && document.activeElement === firstFocusable) {
        e.preventDefault();
        lastFocusable.focus();
      } else if (!e.shiftKey && document.activeElement === lastFocusable) {
        e.preventDefault();
        firstFocusable.focus();
      }
    }
  });
}

High Contrast and Reduced Motion

High Contrast Mode

Test using DevTools rendering emulations:

Reduced Motion

Respect prefers-reduced-motion:

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; }
  * { transition: none !important; }
}

Automated Testing with axe-core

Add axe-core to unit/integration tests:

describe('Accessibility', () => {
  it('popup passes axe-core audit', async () => {
    const results = await axe.run(popupContainer);
    expect(results.violations).toHaveLength(0);
  });
});

WCAG 2.1 AA Compliance Checklist

Common Violations

Missing Alt Text

// Bad
<img src="icon.png">

// Good
<img src="icon.png" alt="Settings gear icon">

Insufficient Contrast

Missing Form Labels

// Bad
<input type="text" placeholder="Email">

// Good
<label for="email">Email</label>
<input type="text" id="email" placeholder="Email">

No Focus Indicators

Never remove outline without replacement:

/* Bad */
*:focus { outline: none; }

/* Good */
*:focus { outline: 2px solid currentColor; outline-offset: 2px; }

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.