vpat
ngoldbla/vpat-skillUse when auditing web projects for WCAG 2.1 / Section 508 accessibility compliance, generating Accessibility Conformance Reports (ACR), or fixing accessibility gaps found during audit
SKILL.md
name: vpat description: Use when auditing web projects for WCAG 2.1 / Section 508 accessibility compliance, generating Accessibility Conformance Reports (ACR), or fixing accessibility gaps found during audit user-invokable: true args:
- name: scope
description: "audit" to run accessibility audit, "acr" to generate the ACR document, or "fix" to remediate findings (default: audit)
required: false
metadata:
author: Dylan Goldblatt
version: 1.0.0
license: MIT
tags:
- accessibility
- wcag
- vpat
- section-508
- a11y
- audit
- acr filePattern:
- "**/*.html"
- "**/*.tsx"
- "**/*.jsx"
- "**/*.css"
- "**/accessibility*"
- "**/a11y*"
- "**/vpat*"
- "**/acr*" bashPattern:
- "lighthouse"
- "axe"
- "pa11y"
VPAT — Accessibility Audit & ACR Generator
Overview
The VPAT (Voluntary Product Accessibility Template) is a standardized template created by the Information Technology Industry Council (ITI). When you fill it out for a specific product, the result is an ACR (Accessibility Conformance Report). This skill automates both the audit process and ACR generation for web applications.
Core standard: WCAG 2.1 Level A and AA — the globally recognized benchmark for web accessibility, referenced by Section 508, EN 301 549, and most procurement policies.
When to Use
- Before a product launch or procurement response
- When a customer or institution requires a VPAT/ACR
- During accessibility remediation sprints
- As a periodic compliance check
Audit Workflow
START
│
▼
┌─────────────────────────┐
│ 1. READ the codebase │ Identify all pages, components,
│ (HTML, CSS, JS/TSX) │ interactive elements, media
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 2. PERCEIVABLE │ Alt text, headings, contrast,
│ (WCAG 1.x criteria) │ text resize, reflow, spacing
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 3. OPERABLE │ Keyboard access, skip links,
│ (WCAG 2.x criteria) │ focus visible, no traps, timing
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 4. UNDERSTANDABLE │ Lang attr, predictable behavior,
│ (WCAG 3.x criteria) │ error identification, labels
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 5. ROBUST │ Valid markup, ARIA name/role/value,
│ (WCAG 4.x criteria) │ status messages
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 6. SECTION 508 CHAPTERS │ Ch3: Functional Performance
│ (beyond WCAG) │ Ch4: Hardware (usually N/A)
│ │ Ch5: Software (usually N/A for web)
│ │ Ch6: Support Documentation
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 7. RATE each criterion │ Supports / Partially Supports /
│ │ Does Not Support / Not Applicable
└────────┬────────────────┘
│
▼
┌─────────────────────────┐
│ 8. GENERATE ACR │ Fill the VPAT 2.4 template
│ (→ reference/ │ with findings and ratings
│ acr-template.md) │
└─────────────────────────┘
Conformance Rating Guide
Use these exact phrases — they are standardized by the ITI VPAT:
| Level | Definition | When to Use |
|---|---|---|
| Supports | At least one method meets the criterion without known defects | All tested functionality passes |
| Partially Supports | Some functionality meets the criterion | Most works, but specific edge cases fail (document which ones) |
| Does Not Support | Majority of product functionality does not meet the criterion | Core functionality fails the criterion |
| Not Applicable | The criterion is irrelevant to the product | e.g., no audio/video content → 1.2.x criteria are N/A |
Remarks are REQUIRED for "Partially Supports" and "Does Not Support". Encouraged for "Supports".
Decision heuristic for Partially vs Does Not Support
Is the CORE user journey affected?
YES → Does Not Support
NO → Are affected areas secondary/edge-case?
YES → Partially Supports (document which areas fail)
NO → Does Not Support
Quick Reference — Code-Level Checks
Perceivable (WCAG 1.x)
| Criterion | What to Check in Code |
|---|---|
| 1.1.1 Non-text Content | Every <img> has alt. Decorative images use alt="" or aria-hidden="true". SVG icons have aria-label or <title>. Icon-only buttons have accessible names. |
| 1.3.1 Info & Relationships | Heading hierarchy (h1→h2→h3, no skips). Landmark regions (<main>, <nav>, <header>, <footer>). Lists use <ul>/<ol>. Tables have <th> with scope. Form inputs have <label>. |
| 1.3.2 Meaningful Sequence | DOM order matches visual order. CSS doesn't reorder content in a way that breaks reading flow. |
| 1.3.4 Orientation | No CSS/JS that locks viewport to portrait or landscape. |
| 1.3.5 Identify Input Purpose | Form inputs use autocomplete attributes where applicable (name, email, tel, address). |
| 1.4.1 Use of Color | Information isn't conveyed by color alone. Error states use icons/text in addition to red. Links are distinguished by more than color (underline or icon). |
| 1.4.3 Contrast (Min) | Text: ≥ 4.5:1 ratio. Large text (≥18pt or ≥14pt bold): ≥ 3:1. Check all color token combinations in CSS custom properties. |
| 1.4.4 Resize Text | Text resizes to 200% without clipping. Use rem/em units, not px for font sizes. |
| 1.4.5 Images of Text | No text baked into images unless essential (logos are exempt). |
| 1.4.10 Reflow | Content works at 320px width without horizontal scrolling. Responsive breakpoints handle narrow viewports. |
| 1.4.11 Non-text Contrast | UI components (buttons, inputs, icons) and meaningful graphics: ≥ 3:1 against adjacent colors. |
| 1.4.12 Text Spacing | Content doesn't break when: line-height 1.5×, paragraph spacing 2×, letter-spacing 0.12em, word-spacing 0.16em. No !important on these properties. |
| 1.4.13 Content on Hover/Focus | Tooltips/popovers: dismissible (Esc), hoverable (mouse can move to them), persistent (don't vanish on their own). |
Operable (WCAG 2.x)
| Criterion | What to Check in Code |
|---|---|
| 2.1.1 Keyboard | All interactive elements reachable via Tab. Click handlers also respond to Enter/Space. No mouse-only interactions. |
| 2.1.2 No Keyboard Trap | Focus can always move away from every component. Modals trap focus correctly AND release it on close. |
| 2.1.4 Character Key Shortcuts | If single-key shortcuts exist, they must be remappable or only active when component is focused. |
| 2.2.1 Timing Adjustable | Any timeouts can be extended/disabled. Session timeouts warn before expiry. |
| 2.2.2 Pause, Stop, Hide | Auto-playing animations/carousels can be paused. Respect prefers-reduced-motion. |
| 2.4.1 Bypass Blocks | "Skip to main content" link as first focusable element. <main id="main-content"> target exists. |
| 2.4.2 Page Titled | <title> is descriptive and unique per page. SPA route changes update document.title. |
| 2.4.3 Focus Order | Tab order follows logical reading order. No tabindex > 0. |
| 2.4.4 Link Purpose | Link text is descriptive (no bare "click here"). External links indicate they open in new tab. |
| 2.4.7 Focus Visible | All focusable elements have visible :focus-visible styles. Check custom components especially. |
| 2.5.1 Pointer Gestures | Multipoint gestures (pinch, swipe) have single-pointer alternatives. |
| 2.5.2 Pointer Cancellation | Click actions fire on mouseup/pointerup, not mousedown. |
| 2.5.3 Label in Name | Visible text labels are included in the accessible name. aria-label doesn't contradict visible text. |
| 2.5.4 Motion Actuation | Shake/tilt features have button alternatives. |
Understandable (WCAG 3.x)
| Criterion | What to Check in Code |
|---|---|
| 3.1.1 Language of Page | <html lang="en"> (or appropriate language code) is set. |
| 3.2.1 On Focus | Focusing an element doesn't trigger a context change (no auto-submit, no navigation on focus). |
| 3.2.2 On Input | Changing a form control doesn't auto-submit or navigate without warning. |
| 3.3.1 Error Identification | Errors are identified in text (not just color). Error messages describe the problem. |
| 3.3.2 Labels or Instructions | All form fields have visible labels. Required fields are indicated. |
Robust (WCAG 4.x)
| Criterion | What to Check in Code |
|---|---|
| 4.1.2 Name, Role, Value | Custom components have appropriate ARIA roles. Interactive elements have accessible names. State changes (expanded, selected, checked) use ARIA attributes. |
Section 508 Chapters
Chapter 3 — Functional Performance Criteria
Applies to all web products. Ensures people with disabilities can use all product functions:
- Without vision → screen reader compatible
- With limited vision → magnification, contrast
- Without color perception → not color-dependent
- Without hearing → captions/transcripts (if audio)
- With limited manipulation → keyboard-operable
- With limited reach → N/A for web (physical)
- With limited language/cognitive → clear labeling, simple navigation
Chapter 4 — Hardware
Typically Not Applicable for web applications. Applies to physical hardware (kiosks, terminals).
Chapter 5 — Software
Typically Not Applicable for web-only products. Applies to native platform software. If the product includes a desktop/mobile app, this chapter applies.
Chapter 6 — Support Documentation and Services
Applies to all products:
- Documentation describes accessibility features
- Documentation is available in accessible formats
- Support services accommodate users with disabilities
ACR Generation
After completing the audit, generate the ACR using the template at → reference/acr-template.md
Fill in:
- Title page — Product name, version, date, evaluator, methods
- WCAG 2.1 Level A table — Rate every A criterion
- WCAG 2.1 Level AA table — Rate every AA criterion
- Section 508 tables — Chapters 3 and 6 (mark 4 and 5 as N/A if web-only)
- Remarks — Specific, actionable details for every non-Supports rating
Common Mistakes
- Vague remarks: "Some issues exist" — instead, describe exactly which components fail and how
- Skipping N/A criteria: Still list them with "Not Applicable" and a brief reason
- Rating "Supports" without testing: Every "Supports" should be verifiable
- Ignoring dynamic content: SPAs must audit route changes, modals, toast notifications, lazy-loaded content
- Forgetting third-party components: Cookie banners, analytics widgets, embedded iframes all need auditing