agentleFS
ncklrsncklrs/claude-chrome-user-testing/skills/wcag-auditor/SKILL.md

wcag-auditor

Skill20 starsChanged 10 months agoMITView on GitHub

This skill provides WCAG 2.1 accessibility audit capabilities, including criteria definitions, check implementations, and scoring logic. Systematically evaluate web pages against WCAG 2.1 Level A and AA success criteria to identify accessibility barriers and provide remediation guidance. WCAG is organized around four principles (POUR): - Perceivable: Information must be presentable to users - Operable: Interface must be usable - Understandable: Information and operation must be understandable - Robust: Content must be interpretable by assistive technologies This skill implements Level A…

2 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

12 rules. About 0 are common, 12 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈12

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    All interactive elements are reachable

    line 65
  2. Distinctive:

    No focus traps exist

    line 67
  3. Distinctive:

    Requirement: All non-text content has a text alternative.

    line 74
  4. Distinctive:

    Pass if: No violations found

    line 88
  5. Distinctive:

    Requirement: All functionality is available via keyboard.

    line 127
  6. Distinctive:

    Check: After focusing each element, verify Tab/Shift+Tab moves focus.

    line 138
  7. Distinctive:

    Requirement: Default human language is programmatically determinable.

    line 180
  8. Distinctive:

    Requirement: No duplicate IDs, elements properly nested.

    line 222
  9. Distinctive:

    Check via browser_snapshot: Verify custom widgets have appropriate ARIA.

    line 248
  10. Distinctive:

    Check: Verify button borders, input borders, focus indicators have sufficient contrast.

    line 294
  11. Distinctive:

    When violations are found, annotate them:

    line 392
  12. Distinctive:

    Add red box annotation with criterion ID as label

    line 396

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

WCAG Auditor Skill

This skill provides WCAG 2.1 accessibility audit capabilities, including criteria definitions, check implementations, and scoring logic.

Purpose

Systematically evaluate web pages against WCAG 2.1 Level A and AA success criteria to identify accessibility barriers and provide remediation guidance.

WCAG 2.1 Overview

WCAG is organized around four principles (POUR):

  • Perceivable: Information must be presentable to users
  • Operable: Interface must be usable
  • Understandable: Information and operation must be understandable
  • Robust: Content must be interpretable by assistive technologies

Conformance Levels

LevelDescriptionRequirements
AMinimumEssential accessibility
AAStandardMost common requirement
AAAEnhancedHighest accessibility

This skill implements Level A and AA checks.

Check Implementation Guide

Using browser_evaluate for DOM Checks

Most WCAG checks can be performed via JavaScript evaluation:

// Example: Check for images without alt text
(function() {
  const images = document.querySelectorAll('img');
  const violations = [];

  images.forEach(function(img) {
    if (!img.hasAttribute('alt')) {
      violations.push({
        element: img.outerHTML.substring(0, 100),
        selector: getSelector(img)
      });
    }
  });

  return { passed: violations.length === 0, violations: violations };
})();

Using browser_snapshot for Accessibility Tree

The accessibility snapshot provides:

  • ARIA roles and properties
  • Accessible names
  • Focusable elements
  • Heading structure

Parse the snapshot to verify semantic structure.

Using browser_press_key for Keyboard Tests

Tab through the page to verify:

  • All interactive elements are reachable
  • Focus order is logical
  • No focus traps exist

Criteria Reference

Level A Criteria

1.1.1 Non-text Content

Requirement: All non-text content has a text alternative.

Check:

// Find images without alt
const imagesWithoutAlt = document.querySelectorAll('img:not([alt])');

// Find inputs type=image without alt
const imageInputsWithoutAlt = document.querySelectorAll('input[type="image"]:not([alt])');

// Find area elements without alt
const areasWithoutAlt = document.querySelectorAll('area:not([alt])');

Pass if: No violations found Severity: Critical (for functional images), Minor (for decorative)


1.3.1 Info and Relationships

Requirement: Information, structure, and relationships are programmatically determinable.

Check:

// Check heading hierarchy
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
let lastLevel = 0;
const violations = [];

headings.forEach(function(h) {
  const level = parseInt(h.tagName[1]);
  if (level > lastLevel + 1) {
    violations.push({ element: h, issue: 'Skipped heading level' });
  }
  lastLevel = level;
});

// Check form labels
const inputs = document.querySelectorAll('input, select, textarea');
inputs.forEach(function(input) {
  if (!input.labels || input.labels.length === 0) {
    if (!input.getAttribute('aria-label') && !input.getAttribute('aria-labelledby')) {
      violations.push({ element: input, issue: 'Missing label' });
    }
  }
});

Severity: Major


2.1.1 Keyboard

Requirement: All functionality is available via keyboard.

Check: Tab through page and verify all interactive elements are reachable.

Severity: Critical


2.1.2 No Keyboard Trap

Requirement: Focus can move away from any component.

Check: After focusing each element, verify Tab/Shift+Tab moves focus.

Severity: Critical


2.4.1 Bypass Blocks

Requirement: Mechanism to bypass repeated content.

Check:

// Look for skip links
const skipLink = document.querySelector('a[href^="#main"], a[href^="#content"], .skip-link');

// Look for landmark regions
const landmarks = document.querySelectorAll('main, [role="main"], nav, [role="navigation"]');

return { hasSkipLink: !!skipLink, hasLandmarks: landmarks.length > 0 };

Severity: Major


2.4.2 Page Titled

Requirement: Web pages have titles describing topic or purpose.

Check:

const title = document.title;
return {
  hasTitle: title && title.trim().length > 0,
  title: title,
  isDescriptive: title && title.length > 5 && !title.match(/^(untitled|home|page)$/i)
};

Severity: Minor


3.1.1 Language of Page

Requirement: Default human language is programmatically determinable.

Check:

const htmlLang = document.documentElement.getAttribute('lang');
const validLangs = ['en', 'es', 'fr', 'de', 'it', 'pt', 'zh', 'ja', 'ko', 'ar', 'ru'];
return {
  hasLang: !!htmlLang,
  lang: htmlLang,
  isValid: validLangs.some(function(l) { return htmlLang && htmlLang.startsWith(l); })
};

Severity: Minor


3.3.2 Labels or Instructions

Requirement: Labels or instructions provided for user input.

Check:

const formFields = document.querySelectorAll('input:not([type="hidden"]), select, textarea');
const violations = [];

formFields.forEach(function(field) {
  const hasLabel = field.labels && field.labels.length > 0;
  const hasAriaLabel = field.getAttribute('aria-label');
  const hasAriaLabelledby = field.getAttribute('aria-labelledby');
  const hasTitle = field.getAttribute('title');

  if (!hasLabel && !hasAriaLabel && !hasAriaLabelledby && !hasTitle) {
    violations.push({ element: field, issue: 'No accessible label' });
  }
});

Severity: Critical


4.1.1 Parsing

Requirement: No duplicate IDs, elements properly nested.

Check:

const allIds = document.querySelectorAll('[id]');
const idMap = {};
const duplicates = [];

allIds.forEach(function(el) {
  const id = el.id;
  if (idMap[id]) {
    duplicates.push(id);
  }
  idMap[id] = true;
});

return { hasDuplicates: duplicates.length > 0, duplicates: duplicates };

Severity: Minor


4.1.2 Name, Role, Value

Requirement: UI components have accessible name, role, and state.

Check via browser_snapshot: Verify custom widgets have appropriate ARIA.

Severity: Critical


Level AA Criteria

1.4.3 Contrast (Minimum)

Requirement: Text has contrast ratio of at least 4.5:1 (3:1 for large text).

Check:

function getLuminance(r, g, b) {
  var a = [r, g, b].map(function(v) {
    v /= 255;
    return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
  });
  return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}

function getContrastRatio(l1, l2) {
  var lighter = Math.max(l1, l2);
  var darker = Math.min(l1, l2);
  return (lighter + 0.05) / (darker + 0.05);
}

// Check text elements
var textElements = document.querySelectorAll('p, span, a, h1, h2, h3, h4, h5, h6, li, td, th, label');
var violations = [];

textElements.forEach(function(el) {
  var style = window.getComputedStyle(el);
  var color = style.color;
  var bgColor = style.backgroundColor;
  // ... calculate contrast
});

Severity: Major


1.4.11 Non-text Contrast

Requirement: UI components have 3:1 contrast ratio.

Check: Verify button borders, input borders, focus indicators have sufficient contrast.

Severity: Major


2.4.7 Focus Visible

Requirement: Keyboard focus indicator is visible.

Check: Tab through elements and verify focus styles are visible.

Severity: Major


Scoring Logic

Calculate Scores

function calculateScore(results) {
  var levelA = results.filter(function(r) { return r.level === 'A'; });
  var levelAA = results.filter(function(r) { return r.level === 'AA'; });

  var aScore = (levelA.filter(function(r) { return r.passed; }).length / levelA.length) * 100;
  var aaScore = (levelAA.filter(function(r) { return r.passed; }).length / levelAA.length) * 100;
  var overall = (results.filter(function(r) { return r.passed; }).length / results.length) * 100;

  return {
    levelA: Math.round(aScore),
    levelAA: Math.round(aaScore),
    overall: Math.round(overall),
    grade: getGrade(overall)
  };
}

function getGrade(score) {
  if (score >= 90) return 'A';
  if (score >= 80) return 'B';
  if (score >= 70) return 'C';
  if (score >= 60) return 'D';
  return 'F';
}

Remediation Guidance

Common Fixes

IssueFix
Missing alt textAdd descriptive alt attribute
Missing form labelsAssociate label with for attribute
Low contrastIncrease color difference
No skip linkAdd "Skip to main content" link
Missing langAdd lang attribute to html element
Keyboard trapEnsure Tab/Escape can exit
No focus visibleAdd :focus styles with outline

Code Examples

Adding alt text:

<!-- Before -->
<img src="chart.png">

<!-- After -->
<img src="chart.png" alt="Sales chart showing 20% growth in Q4">

Adding form label:

<!-- Before -->
<input type="email" placeholder="Email">

<!-- After -->
<label for="email">Email address</label>
<input type="email" id="email">

Adding skip link:

<a href="#main-content" class="skip-link">Skip to main content</a>
<!-- ... header/nav ... -->
<main id="main-content">

Improving contrast:

/* Before: 2.5:1 ratio */
.text { color: #999; background: #fff; }

/* After: 4.6:1 ratio */
.text { color: #666; background: #fff; }

Integration with Screenshot Annotator

When violations are found, annotate them:

  1. For each violation with identifiable element
  2. Get element position
  3. Add red box annotation with criterion ID as label
  4. Take screenshot
  5. Include in report

Report Templates

See commands/wcag-audit.md for full report format templates.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.