Vitaly — Accessible Web Form Design
Enforces Vitaly Friedman's best practices for accessible, efficient, inclusive web forms. Derived from Smashing Magazine articles, the 76-question Web Forms Checklist, Smart Interface Design Patterns, and 2025 inclusive design workshops.
Announce at start: "Applying Vitaly's accessible form design patterns."
When to Use
- Generating form components (React, HTML, or any framework)
- Auditing existing form code for accessibility and UX
- Reviewing pull requests that touch form markup
- Designing form layouts and interaction patterns
Core Rules (Never Violate)
1. Labels & Field Identification
- Succinct labels (1-2 words, sentence case) placed above inputs
- Never use placeholders as the only label — they vanish on focus
- Floating labels must keep a persistent visible label via
<label> element
- Mark required fields with asterisk + legend, OR mark optional fields with "(optional)" — the latter is preferred for long forms
- Never rely on color alone to convey required/error state
- Group related fields with
<fieldset> + <legend>
2. Form Structure & Layout
- Single-column layout only — creates a straight, predictable scan path
- Ask only what is truly needed — every extra field reduces completion rate
- Order fields from the user's mental model (name → email → details), not the database schema
- Display 5-7 fields at a time; use progressive disclosure for complex forms
- Never put text-input forms inside modals on mobile
3. Inputs & Interaction
- Full keyboard accessibility: every element Tab-reachable, operable with Enter/Space
- Visible
:focus-visible styles on all interactive elements — never remove focus outlines
- Autofocus the first field with a clear visual cue
- Match
inputmode/type to the right mobile keyboard (email, tel, numeric)
- Use
autocomplete attributes on every applicable field
- Large touch targets for checkboxes/radios (minimum 44x44px)
- Predictable tab order — no surprises
- Password fields: include accessible show/hide toggle with
aria-pressed
4. Validation & Error Handling
- Inline validation after field completion (onBlur), not on every keystroke
- Hybrid strategy: "reward early" (show green check on valid), "punish late" (show error only after blur on invalid)
- Link errors to fields via
aria-describedby pointing to the error element
- Use
aria-live="polite" regions for dynamic error announcements
- Show total error count above submit button AND in page
<title>
- Never disable the submit button without explanation — use
aria-disabled + explanatory text so focus and tooltips still work
- Error messages must be specific and actionable: "Email address must include @" not "Invalid input"
- Design to prevent errors: smart defaults, input masks, autocomplete
5. Custom Controls
- Style checkboxes/radios with SVGs but keep native elements in the accessibility tree (inclusive hiding)
- Follow WAI-ARIA Authoring Practices for toggles, autocompletes, selects
- Prefer semantic
<button type="submit"> over styled divs
- CAPTCHA: use progressive or invisible alternatives when possible
6. Mobile & Responsive
- Match virtual keyboard to field type via
inputmode
- No forms inside modals/popups on mobile
- Persist user input on page refresh (localStorage or form state management)
- Ensure touch targets are large enough (44x44px minimum)
7. Inclusive Design (2025)
- Support
prefers-reduced-motion for animations
- High contrast mode support
- Never rely on color alone — pair with icons or text
- Test with real assistive technology (screen readers, keyboard-only navigation)
Audit Workflow
When auditing form code, follow this checklist:
- Scan structure: Single column? Logical field order? Minimal fields?
- Check labels: Every input has a visible
<label> with htmlFor/for? No placeholder-only labels?
- Check keyboard: All elements Tab-reachable? Visible focus styles? Logical tab order?
- Check validation: Inline errors on blur?
aria-describedby linking? aria-live for dynamic errors? Error count above submit?
- Check submit: Button not disabled without explanation? Clear action label ("Submit Feedback" not "Submit")?
- Check mobile: Correct
inputmode/type? Large touch targets? No form-in-modal?
- Check accessibility:
aria-invalid on errored fields? aria-required or required attribute? autocomplete attributes?
Output a compliance table:
| Category | Status | Issues |
|-----------------------|--------|--------|
| Labels | ✓/✗ | ... |
| Structure | ✓/✗ | ... |
| Keyboard | ✓/✗ | ... |
| Validation | ✓/✗ | ... |
| Submit | ✓/✗ | ... |
| Mobile | ✓/✗ | ... |
| Accessibility (ARIA) | ✓/✗ | ... |
Generation Mode
When generating form components, apply all core rules automatically. The output component must:
- Use semantic HTML elements (
<form>, <label>, <fieldset>, <legend>)
- Include
htmlFor on every <Label> matching the input id
- Include
aria-describedby pointing to help text and error elements
- Include
aria-invalid={true} when a field has an error
- Include
aria-live="polite" on error message containers
- Use
onBlur validation (not onChange for every keystroke)
- Show a character counter with
aria-live="polite" for textareas with limits
- Replace the form with a confirmation screen on successful submission
- Show a loading spinner + disabled button during submission
- Include
autocomplete attributes on name, email, phone, address fields
- Use
inputMode for mobile keyboard optimization
- Mark optional fields with "(optional)" in the label text
- Mark required fields with a red asterisk + screen-reader text
Form Type Patterns
Consult references/form-patterns.md for type-specific best practices:
- Feedback surveys, NPS, CSAT
- Contact forms
- Registration / signup
- Multi-step wizards
- Medical intake
- Job applications
- Payment forms
- File upload forms
Additional Resources
Reference Files
references/form-patterns.md — Detailed best practices per form type (survey, registration, wizard, payment, etc.)
references/aria-reference.md — Quick reference for ARIA attributes used in forms
1---2name: vitaly3description: This skill should be used when generating web form components, auditing form accessibility, reviewing form UX, or when the user asks to "check form accessibility", "audit this form", "apply form best practices", "make this form accessible", "review form UX". Also triggers on form generation tasks where the output is a React form component. Based on Vitaly Friedman's (Smashing Magazine) accessible web form design patterns.4---56# Vitaly — Accessible Web Form Design78Enforces Vitaly Friedman's best practices for accessible, efficient, inclusive web forms. Derived from Smashing Magazine articles, the 76-question Web Forms Checklist, Smart Interface Design Patterns, and 2025 inclusive design workshops.910**Announce at start:** "Applying Vitaly's accessible form design patterns."1112## When to Use1314- Generating form components (React, HTML, or any framework)15- Auditing existing form code for accessibility and UX16- Reviewing pull requests that touch form markup17- Designing form layouts and interaction patterns1819## Core Rules (Never Violate)2021### 1. Labels & Field Identification2223- Succinct labels (1-2 words, sentence case) placed **above** inputs24- Never use placeholders as the only label — they vanish on focus25- Floating labels must keep a persistent visible label via `<label>` element26- Mark required fields with asterisk + legend, OR mark optional fields with "(optional)" — the latter is preferred for long forms27- Never rely on color alone to convey required/error state28- Group related fields with `<fieldset>` + `<legend>`2930### 2. Form Structure & Layout3132- **Single-column layout only** — creates a straight, predictable scan path33- Ask only what is truly needed — every extra field reduces completion rate34- Order fields from the user's mental model (name → email → details), not the database schema35- Display 5-7 fields at a time; use progressive disclosure for complex forms36- Never put text-input forms inside modals on mobile3738### 3. Inputs & Interaction3940- Full keyboard accessibility: every element Tab-reachable, operable with Enter/Space41- Visible `:focus-visible` styles on all interactive elements — never remove focus outlines42- Autofocus the first field with a clear visual cue43- Match `inputmode`/`type` to the right mobile keyboard (`email`, `tel`, `numeric`)44- Use `autocomplete` attributes on every applicable field45- Large touch targets for checkboxes/radios (minimum 44x44px)46- Predictable tab order — no surprises47- Password fields: include accessible show/hide toggle with `aria-pressed`4849### 4. Validation & Error Handling5051- **Inline validation after field completion** (onBlur), not on every keystroke52- Hybrid strategy: "reward early" (show green check on valid), "punish late" (show error only after blur on invalid)53- Link errors to fields via `aria-describedby` pointing to the error element54- Use `aria-live="polite"` regions for dynamic error announcements55- Show total error count above submit button AND in page `<title>`56- **Never disable the submit button without explanation** — use `aria-disabled` + explanatory text so focus and tooltips still work57- Error messages must be specific and actionable: "Email address must include @" not "Invalid input"58- Design to prevent errors: smart defaults, input masks, autocomplete5960### 5. Custom Controls6162- Style checkboxes/radios with SVGs but keep native elements in the accessibility tree (inclusive hiding)63- Follow WAI-ARIA Authoring Practices for toggles, autocompletes, selects64- Prefer semantic `<button type="submit">` over styled divs65- CAPTCHA: use progressive or invisible alternatives when possible6667### 6. Mobile & Responsive6869- Match virtual keyboard to field type via `inputmode`70- No forms inside modals/popups on mobile71- Persist user input on page refresh (localStorage or form state management)72- Ensure touch targets are large enough (44x44px minimum)7374### 7. Inclusive Design (2025)7576- Support `prefers-reduced-motion` for animations77- High contrast mode support78- Never rely on color alone — pair with icons or text79- Test with real assistive technology (screen readers, keyboard-only navigation)8081## Audit Workflow8283When auditing form code, follow this checklist:84851. **Scan structure**: Single column? Logical field order? Minimal fields?862. **Check labels**: Every input has a visible `<label>` with `htmlFor`/`for`? No placeholder-only labels?873. **Check keyboard**: All elements Tab-reachable? Visible focus styles? Logical tab order?884. **Check validation**: Inline errors on blur? `aria-describedby` linking? `aria-live` for dynamic errors? Error count above submit?895. **Check submit**: Button not disabled without explanation? Clear action label ("Submit Feedback" not "Submit")?906. **Check mobile**: Correct `inputmode`/`type`? Large touch targets? No form-in-modal?917. **Check accessibility**: `aria-invalid` on errored fields? `aria-required` or `required` attribute? `autocomplete` attributes?9293Output a compliance table:9495```96| Category | Status | Issues |97|-----------------------|--------|--------|98| Labels | ✓/✗ | ... |99| Structure | ✓/✗ | ... |100| Keyboard | ✓/✗ | ... |101| Validation | ✓/✗ | ... |102| Submit | ✓/✗ | ... |103| Mobile | ✓/✗ | ... |104| Accessibility (ARIA) | ✓/✗ | ... |105```106107## Generation Mode108109When generating form components, apply all core rules automatically. The output component must:1101111. Use semantic HTML elements (`<form>`, `<label>`, `<fieldset>`, `<legend>`)1122. Include `htmlFor` on every `<Label>` matching the input `id`1133. Include `aria-describedby` pointing to help text and error elements1144. Include `aria-invalid={true}` when a field has an error1155. Include `aria-live="polite"` on error message containers1166. Use `onBlur` validation (not onChange for every keystroke)1177. Show a character counter with `aria-live="polite"` for textareas with limits1188. Replace the form with a confirmation screen on successful submission1199. Show a loading spinner + disabled button during submission12010. Include `autocomplete` attributes on name, email, phone, address fields12111. Use `inputMode` for mobile keyboard optimization12212. Mark optional fields with "(optional)" in the label text12313. Mark required fields with a red asterisk + screen-reader text124125## Form Type Patterns126127Consult `references/form-patterns.md` for type-specific best practices:128- Feedback surveys, NPS, CSAT129- Contact forms130- Registration / signup131- Multi-step wizards132- Medical intake133- Job applications134- Payment forms135- File upload forms136137## Additional Resources138139### Reference Files140141- **`references/form-patterns.md`** — Detailed best practices per form type (survey, registration, wizard, payment, etc.)142- **`references/aria-reference.md`** — Quick reference for ARIA attributes used in forms