Form a11y
Web accessibility agent skills — 23 cite-backed skills covering APG widget patterns, audit tooling, ARIA guidance, cognitive accessibility, and more. Works with Claude Code, Codex CLI, and Gemini CLI.
npx -y skills add xrnavigation/web-a11y-plugin --skill form-a11yAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Guides comprehensive form accessibility beyond basic labels — error messaging and association, validation patterns, field grouping, accessible authentication (WCAG 2.2), redundant entry prevention, and autocomplete attributes. Auto-invokes when creating forms, validation logic, authentication flows, or multi-step form wizards.
SKILL.md
13.5 KB, as published. Nobody here has run it
Form Accessibility
"The best error message is the one that never shows up." — Thomas Fuchs
Forms are the primary way users provide information on the web. Getting form accessibility wrong locks people out of purchases, registrations, healthcare portals, and government services. This skill covers everything beyond basic <label> + <input> pairing.
1. Error Association
Use aria-describedby + aria-invalid to connect error messages to fields. This is the proven, cross-browser pattern.
<label for="email">Email</label>
<input id="email" type="email"
aria-describedby="email-error"
aria-invalid="true">
<span id="email-error">Enter a valid email address, e.g. [email protected]</span>
Rules
- Set
aria-invalid="true"when a field has an error. Remove the attribute entirely (not"false") when valid. - Never set
aria-invalidbefore the user interacts. Do not mark required fields invalid on page load. - Use
aria-describedbyto point the input to the error message element'sid. Screen readers announce the description when the field receives focus. - Multiple descriptions: space-separate IDs to include both a hint and an error:
<input id="phone" type="tel"
aria-describedby="phone-hint phone-error"
aria-invalid="true">
<span id="phone-hint">Format: (555) 123-4567</span>
<span id="phone-error">Phone number is required.</span>
- Do NOT use
aria-liveon individual field errors. Roselli's testing across seven SR/browser combinations found thataria-live="assertive"on field errors clips the next field name announcement. Chromium/JAWS already treatsaria-describedbyas an assertive live region, doubling announcements if you also addaria-live. (Roselli, 2023) - Do NOT use
aria-errormessagein production yet. Support is insufficient as of 2024-2025 — TalkBack has no support, iOS VoiceOver/Safari only partial. Continue usingaria-describedby. (Cerovac, 2024)
Limitation
Changes to aria-describedby content while the input is focused will not trigger re-announcement — the user must re-focus the field. (Roselli, 2022)
2. Validation Patterns
Timing
- Validate on blur, not on every keystroke. The
inputevent fires errors before the user finishes typing — this is disruptive. - Refinement: only trigger blur validation if the field value actually changed. This prevents false errors from accidental focus (scrolling, tabbing past).
- Always validate on submit. Client-side validation can be bypassed; always validate server-side as well.
(TetraLogical, 2024; Smashing Magazine, 2023)
Inline Errors
- Display error messages near their associated field.
- Use distinctive styling — not color alone (WCAG 1.4.1). Add an icon, text prefix ("Error:"), or border change alongside color.
- Associate each error to its field via
aria-describedby.
Error Summary
For longer forms, display a summary of all errors above the form (or before the submit button):
- Include links to each invalid field.
- Set focus to the summary container after submission.
- Use
aria-live="assertive"on the summary container — not on individual field errors.
For short forms (2-3 fields), focusing the first invalid field with HTMLElement.focus() is sufficient — the screen reader announces the error via aria-describedby.
Recommended: Combined Approach
Use both an error summary and inline errors. The summary provides orientation ("3 errors found"); inline errors provide context at each field. (WebAIM)
3. Field Grouping (fieldset/legend)
Use <fieldset> and <legend> to group related controls. The <legend> acts as the group label — screen readers announce it when a user enters the fieldset.
When to Use
- Radio button groups — the legend provides the group question
- Checkbox groups — when checkboxes share a common category
- Address blocks — shipping vs. billing address sections
- Related field sets — e.g., "Emergency Contact" fields
<fieldset>
<legend>Shipping Address</legend>
<label for="street">Street</label>
<input id="street" type="text" autocomplete="shipping street-address">
<!-- more fields -->
</fieldset>
When NOT to Use
- Do not wrap the entire form in a single fieldset — it adds noise without value.
- A single input with its own
<label>does not need a fieldset. - Use fieldset only when fields share a relationship that needs a group label.
4. Required Fields
Visual Indicators
- Use text "(required)" near the label, not asterisks alone.
- If using asterisks, include a legend at the top of the form: "Fields marked with * are required."
- Never rely on color alone (WCAG 1.4.1).
<label for="name">Full Name <span aria-hidden="true">*</span>
<span class="sr-only">(required)</span>
</label>
<input id="name" type="text" required>
required vs. aria-required="true"
| Attribute | SR announces "required" | Browser-native validation | Prevents empty submission |
|---|---|---|---|
required | Yes | Yes | Yes |
aria-required="true" | Yes | No | No |
Use required when browser-native validation is acceptable. Use aria-required="true" when you need custom validation UX and want to suppress browser tooltips (add novalidate to the <form>).
5. Accessible Authentication (WCAG 2.2)
SC 3.3.8 — Level AA
A cognitive function test (remembering a password, solving a puzzle, transcribing a code) must NOT be required for authentication unless:
- Alternative — another method exists that doesn't require the test
- Mechanism — assistance is available (password manager, paste)
- Object Recognition — the test uses object recognition (AA only)
- Personal Content — the test uses content the user provided (AA only)
SC 3.3.9 — Level AAA
Same as 3.3.8, but only the Alternative and Mechanism exceptions remain.
What Complies
- Username/password with proper
autocompleteattributes (username,current-password,new-password) - Paste is not blocked on authentication fields
- WebAuthn / passkeys (fingerprint, face, PIN)
- Third-party OAuth (Sign in with Google, etc.)
- Email-link / magic link authentication
- Multi-factor with hardware tokens, QR codes, or device notifications
What Fails
- Blocking paste on password or verification code fields
- Requiring manual transcription of verification codes without copy/paste
- CAPTCHAs or puzzles with no alternative
- Requiring memorization without allowing password managers
Implementation Checklist
<!-- Login form — compliant -->
<form>
<label for="user">Username</label>
<input id="user" type="text" autocomplete="username">
<label for="pass">Password</label>
<input id="pass" type="password" autocomplete="current-password">
<!-- Do NOT add onpaste="return false" -->
<button type="submit">Sign In</button>
</form>
6. Redundant Entry (WCAG 2.2)
SC 3.3.7 — Level A
Information previously entered by the user that is required again in the same process must be either auto-populated or available for the user to select.
Exceptions: re-entry is essential, required for security (password confirmation), or the information is no longer valid.
Implementation Techniques
- "Billing address same as shipping" checkbox
- Pre-populate fields from earlier steps (allow edits)
- Dropdowns populated from previous input
- Retain field values after validation errors — never clear the form on failed submission
- Pre-fill search terms on results pages
7. Autocomplete Attributes
The autocomplete attribute enables browsers and password managers to auto-fill fields. Required for WCAG 1.3.5 (Identify Input Purpose) and supports accessible authentication (3.3.8/3.3.9).
Quick Reference
| Purpose | Values |
|---|---|
| Identity | name, given-name, family-name, nickname, username, organization |
| Authentication | current-password, new-password, one-time-code |
| Address | street-address, address-line1, address-line2, address-level2 (city), address-level1 (state), country, postal-code |
| Payment | cc-name, cc-number, cc-exp, cc-exp-month, cc-exp-year, cc-csc |
| Contact | tel, email, url |
| Personal | bday, sex, language, photo |
Modifiers
- Scope:
section-{name}groups related fields (e.g.,section-emergency-contact) - Purpose:
shipping,billingprefix address/contact fields - Contact type:
home,work,mobileprefix tel/email fields - WebAuthn:
webauthnfor passkey/credential fields
<input autocomplete="shipping address-line1" name="ship-street">
<input autocomplete="billing cc-number" name="card">
<input autocomplete="section-emergency-contact tel" name="emergency-phone">
For the complete list of all autocomplete values, see: ${CLAUDE_SKILL_DIR}/references/autocomplete-values.md
8. Common Mistakes
These are real patterns from accessibility audits. Each is cited.
- Blocking paste on password fields — prevents password manager use, fails WCAG 3.3.8. (W3C)
- Validating on every keystroke — fires errors before the user finishes typing. Validate on blur. (TetraLogical)
aria-liveon individual field errors — clips next field announcement in multiple SR/browser combos. Usearia-liveonly on error summaries. (Roselli)aria-invalidbefore user interaction — do not mark required fields invalid on page load. (Deque)- Color alone for error indication — red borders without icons or text fails WCAG 1.4.1. (Smashing Magazine)
- Vague error messages — "Invalid input" is unhelpful. Provide specific guidance: "Enter a date in MM/DD/YYYY format." (WebAIM)
- Clearing form on validation failure — destroys user input, fails the spirit of SC 3.3.7. (W3C)
- Missing
autocompleteon login fields — withoutautocomplete="username"andautocomplete="current-password", password managers can't autofill, risking WCAG 3.3.8 failure. (W3C) aria-labelinstead of visible<label>— not translated by many localization tools, doesn't expand click target. Use<label for="...">first. (Roselli)- Using
aria-errormessagein production — insufficient SR support as of 2024-2025. Usearia-describedby. (Cerovac) - Disabled form controls — not focusable, not announced by some screen readers, no explanation of why disabled. Prefer keeping controls enabled and validating on submission. (Roselli)
- Wrapping entire field content in
<label>— confuses screen readers about actual label text and creates click-conflict with interactive elements inside the label. (Smashing Magazine)
For detailed patterns and anti-patterns, see: ${CLAUDE_SKILL_DIR}/references/common-mistakes.md
9. Cross-References
live-regions— foraria-liveusage on error summaries and dynamic content announcementscognitive-a11y— for cognitive accessibility considerations (clear language, error recovery, timeouts)aria-decision-framework— for when to use ARIA vs. native HTML elements
For detailed reference material:
${CLAUDE_SKILL_DIR}/references/error-association-patterns.md— complete error association patterns with SR test results${CLAUDE_SKILL_DIR}/references/autocomplete-values.md— full autocomplete attribute value list${CLAUDE_SKILL_DIR}/references/common-mistakes.md— anti-patterns with citations${CLAUDE_SKILL_DIR}/references/sources.yaml— provenance for all cited sources