Agent Skill
2/7/2026

web-standards

Static HTML/CSS/ARIA analysis without requiring a browser. Use this skill when analyzing code for semantic HTML issues, ARIA validity, landmark structure, heading hierarchy, form labeling, or any accessibility problems detectable from source code. Queries aria-mcp for ARIA rules and wcag-mcp for success criteria mapping. Part of the a11y-orchestrator workflow.

J
joe
1GitHub Stars
2Views
npx skills add joe-watkins/a11y-devkit

SKILL.md

Nameweb-standards
DescriptionStatic HTML/CSS/ARIA analysis without requiring a browser. Use this skill when analyzing code for semantic HTML issues, ARIA validity, landmark structure, heading hierarchy, form labeling, or any accessibility problems detectable from source code. Queries aria-mcp for ARIA rules and wcag-mcp for success criteria mapping. Part of the a11y-orchestrator workflow.

name: web-standards description: Static HTML/CSS/ARIA analysis without requiring a browser. Use this skill when analyzing code for semantic HTML issues, ARIA validity, landmark structure, heading hierarchy, form labeling, or any accessibility problems detectable from source code. Queries aria-mcp for ARIA rules and wcag-mcp for success criteria mapping. Part of the a11y-orchestrator workflow.

Web Standards Analyzer

Static accessibility analysis of HTML, CSS, and ARIA without browser execution.

Analysis Categories

Work through each category, noting any issues found.

1. Semantic HTML

Check for proper semantic element usage:

CheckIssue PatternFix Direction
Buttons<div onclick>, <span onclick>, <a role="button">Use <button>
Links<span onclick> for navigation, <button> with href behaviorUse <a href>
Headings<div class="title">, skipped levels (h1→h3)Use <h1>-<h6> in order
ListsSeries of <div> for list itemsUse <ul>/<ol> with <li>
Tables<div> grids for tabular dataUse <table> with proper headers
Nav<div class="nav">Use <nav> landmark
MainContent without <main>Wrap primary content in <main>
FormsInputs without associated labelsAdd <label for="">

2. ARIA Validity

Query aria-mcp for authoritative ARIA rules:

  • get-role("button") → Returns role requirements
  • validate-role-attributes("button", ["aria-pressed"]) → Validates ARIA usage
  • get-prohibited-attributes("button") → Returns disallowed attributes

Check for:

Invalid ARIA on semantic elements:

  • <button role="button"> — redundant
  • <a role="link"> — redundant
  • <a role="button"> — misuse (use <button> instead)

Missing required ARIA:

  • Custom widgets without appropriate roles
  • Interactive elements without accessible names
  • Dynamic content without live regions

Invalid ARIA combinations:

  • aria-checked on non-checkbox/switch roles
  • aria-expanded on elements without expandable content
  • aria-selected outside selection contexts

Query aria-mcp for role-specific requirements when custom widgets are found:

  • get-required-attributes("tabpanel") → Returns required attributes
  • get-required-context("tab") → Returns required parent context
  • suggest-role("dropdown menu") → Suggests appropriate role

3. Landmark Structure

Check page has appropriate landmarks:

LandmarkExpectedIssue If Missing
<main> or role="main"One per pageNo main landmark
<nav> or role="navigation"For navigationNavigation not identified
<header> or role="banner"Top-level headerNo banner landmark
<footer> or role="contentinfo"Top-level footerNo content info

Watch for:

  • Multiple <main> elements
  • Landmarks inside landmarks of same type
  • Overuse of landmarks (every section doesn't need one)

3.5 Document & Metadata (Static)

Quick static checks that frequently correlate with accessibility failures:

CheckWhat to look forWhy it matters
Page language<html lang="..."> present and valid BCP 47 tagEnables correct screen reader pronunciation (WCAG 3.1.1)
Document title<title> present and meaningfulHelps users identify the page (WCAG 2.4.2)
ID uniquenessDuplicate id values in the same documentBreaks label/description references and scripting (WCAG 4.1.1)
Invalid nestingInteractive inside interactive (e.g., <button><a>), headings inside links used incorrectly, etc.Often causes AT/keyboard inconsistencies (WCAG 4.1.1 / 1.3.1)

Notes:

  • Static analysis can flag missing/invalid lang, missing <title>, duplicate IDs, and common invalid nesting patterns with high confidence.
  • If the snippet is partial (component-only), note “document-level checks not applicable” rather than failing.

4. Heading Hierarchy

Verify heading structure:

  1. Page should have exactly one <h1>
  2. Headings should not skip levels (h1→h2→h3, not h1→h3)
  3. Headings should reflect content hierarchy
  4. Visual headings should be semantic headings

Query wcag-mcp: get-criterion("1.3.1") for Info and Relationships

5. Form Accessibility

Check all form controls:

ElementRequiredCheck
<input>LabelHas <label for=""> or aria-label
<select>LabelHas associated label
<textarea>LabelHas associated label
Required fieldsIndicationrequired or aria-required
ErrorsAssociationaria-describedby to error message
GroupsLabeling<fieldset>/<legend> for radio/checkbox groups

Invalid patterns:

  • Placeholder as only label
  • Label not programmatically associated
  • Hidden label without accessible alternative

5.5 Accessible Name, Role, Value (ANRV)

Static heuristics for “can a user perceive/operate this control with AT?”

Control patternCheckCommon issue
Buttons/linksHas an accessible name (text content OR aria-label OR aria-labelledby)Icon-only controls with no name (WCAG 4.1.2 / 2.4.4)
InputsName is programmatically associated (<label for>, aria-labelledby, or aria-label)Placeholder-only naming (WCAG 3.3.2 / 1.3.1)
Custom widgetsRole is appropriate + required ARIA attributes presentMissing role/required props; mismatched role/props (WCAG 4.1.2)
ARIA referencesaria-labelledby / aria-describedby targets exist + are uniqueBroken references (often due to duplicate IDs) (WCAG 4.1.1)

Implementation note:

  • Prefer visible text + semantic HTML.
  • Use aria-mcp when a custom widget is detected to confirm required attributes/required context for the chosen role.

6. Image Accessibility

Check all images and graphics:

ElementCheckIssue
<img>Has alt attributeMissing alt
Informative <img>alt describes contentEmpty alt on meaningful image
Decorative <img>alt=""Descriptive alt on decorative image
<svg>Has accessible name or aria-hiddenSVG not labeled or hidden
Icon fontsHas text alternativeIcon-only with no text

Query wcag-mcp: get-criterion("1.1.1") for Non-text Content

7. Keyboard Accessibility

Static checks for keyboard support:

CheckIssue Pattern
tabindex > 0Disrupts natural tab order
tabindex="-1" on interactiveRemoves from tab order
onclick without keyboard handlerMouse-only interaction
Non-focusable interactiveCustom widget without tabindex="0"

Additional static red flags:

  • onmousedown, onmouseup, onpointerdown handlers without equivalent keyboard activation
  • Click handlers attached to non-interactive elements without:
    • role, keyboard handlers, and focusability (tabindex="0")
  • CSS removing focus indicators (also see Text and Contrast):
    • :focus { outline: none; }
    • :focus-visible { outline: none; }

When present, capture:

  • The exact element snippet
  • The event handler pattern
  • Whether a semantic element (<button>, <a href>) would remove the need for scripting

Query wcag-mcp: get-criterion("2.1.1") for Keyboard

8. Text and Contrast (CSS)

Check CSS for potential issues:

CheckIssue Pattern
outline: noneRemoves focus indicator
outline: 0Removes focus indicator
Fixed font sizesMay prevent text resize
user-select: noneMay prevent text selection

Query wcag-mcp: get-criterion("2.4.7") for Focus Visible, get-criterion("1.4.4") for Resize Text

Output Format

Report issues in this structure:

## Static Analysis Results

Found X accessibility issues:

### Issue 1: [Brief description]

- **Location:** [file:line or element path]
- **Category:** [Semantic HTML/ARIA/Landmarks/etc.]
- **Severity:** [Critical/Serious/Moderate/Minor]
- **WCAG:** [Success criterion from wcag-mcp]
- **Confidence:** [High/Medium/Low] (Static-only signal strength)
- **Instances:** [count + brief list of selectors/paths]
- **Evidence:** [snippet(s), selector(s), relevant attribute values, and why it fails]
- **Recommended Verification:** [manual check(s) needed in browser/AT, if any]
- **Code:**
  ```html
  [problematic code]
  • Problem: [What's wrong]

---

## Severity Guidelines

| Severity | Criteria                                             |
| -------- | ---------------------------------------------------- |
| Critical | Blocks access entirely (no keyboard, no name)        |
| Serious  | Major barrier (skipped headings, no labels)          |
| Moderate | Degrades experience (redundant ARIA, poor semantics) |
| Minor    | Best practice violation (optimization opportunities) |

## Static Analysis Limitations (Important)

Static analysis is best at detecting:
- Missing semantics (wrong element choice, missing labels, missing landmarks/headings)
- Invalid/unsupported ARIA usage and broken ARIA references
- Focus indicator removal in CSS

Static analysis is limited for:
- Color contrast (needs computed colors)
- Keyboard operability of scripted widgets (needs runtime behavior)
- Screen reader output, focus order, and dynamic announcements (needs browser + AT)

When an issue depends on runtime behavior, still file it, but mark **Confidence: Medium/Low** and add **Recommended Verification** steps.

## MCP Server Queries

When you encounter these situations, query the referenced MCP server:

| Situation              | Query MCP         | Example Tool                             |
| ---------------------- | ----------------- | ---------------------------------------- |
| Custom ARIA widget     | `aria-mcp`        | `get-required-attributes("dialog")`      |
| WCAG criterion details | `wcag-mcp`        | `get-techniques-for-criterion("1.3.1")`  |
| Correct implementation | `magentaa11y-mcp` | `get_component_developer_notes("modal")` |
Skills Info
Original Name:web-standardsAuthor:joe