$npx -y skills add mgifford/accessibility-skills --skill speech-recognitionLoad this skill whenever the project must support speech input or voice control — dictation, "click by voice" grammars, Dragon NaturallySpeaking, Voice Control (iOS/macOS), Voice Access (Android), or any interface where users activate controls by speaking. Under no circumstances
| 1 | # Speech Recognition Accessibility Skill |
| 2 | |
| 3 | > **Canonical source**: `examples/SPEECH_RECOGNITION_ACCESSIBILITY_BEST_PRACTICES.md` in `mgifford/ACCESSIBILITY.md` |
| 4 | > This skill is derived from that file. When in doubt, the example is authoritative. |
| 5 | |
| 6 | Apply these rules when implementing or reviewing any interface that must |
| 7 | support speech input or voice control. |
| 8 | **Load alongside `keyboard/SKILL.md` — speech tools often rely on keyboard |
| 9 | and pointer emulation, so keyboard requirements are a foundation, not a substitute.** |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## Core Mandate |
| 14 | |
| 15 | Speech recognition can dictate text, navigate interfaces, activate controls, |
| 16 | emulate keyboard input, and operate a pointer. Speech recognition is not the |
| 17 | same as speaker recognition — speech recognition interprets words and |
| 18 | commands; speaker recognition tries to identify who is speaking. |
| 19 | |
| 20 | **Core principles:** |
| 21 | 1. Use visible, persistent labels — people must be able to determine what to say without guessing a hidden name |
| 22 | 2. Match visible labels and accessible names — if a control has visible text, its accessible name must contain that text |
| 23 | 3. Use native semantics — correct HTML names/roles/states/values/keyboard behavior give speech tools reliable information |
| 24 | 4. Support more than direct label activation — keyboard emulation, name/number overlays, and pointer emulation vary by product |
| 25 | 5. Do not require fine pointer control — provide alternatives to dragging, path gestures, and precise spatial interaction |
| 26 | 6. Accept input from more than key events — dictation, paste, and autocomplete may change a field without firing expected keystrokes |
| 27 | 7. Provide clear feedback — expose changed state, errors, confirmations, and results visually and programmatically |
| 28 | 8. Test the supported environments — commands, overlays, and behavior vary by product, platform, and version |
| 29 | |
| 30 | **Who uses speech input:** people with limited movement/strength/dexterity/ |
| 31 | reach/endurance; repetitive strain injuries, pain, tremors, or fatigue; |
| 32 | people using speech instead of or alongside a keyboard/pointer; people with |
| 33 | cognitive/learning disabilities who find dictation easier than typing; |
| 34 | temporary or situational limitations; people combining speech with a screen |
| 35 | reader, magnifier, or switch. **Speech users are not necessarily sighted** — |
| 36 | do not design or test on the assumption that everyone using speech can see a |
| 37 | label, overlay, pointer, focus indicator, or visual result. |
| 38 | |
| 39 | --- |
| 40 | |
| 41 | ## Severity Scale (this skill) |
| 42 | |
| 43 | | Level | Meaning | |
| 44 | |---|---| |
| 45 | | **Critical** | A control cannot be activated by any speech-tool method (name, overlay, or keyboard/pointer emulation) | |
| 46 | | **Serious** | Accessible name doesn't contain the visible label; validation depends only on `keydown` and silently rejects dictated/pasted input | |
| 47 | | **Moderate** | Repeated controls are hard to disambiguate; icon-only control has no accessible name | |
| 48 | | **Minor** | Hidden context inserted before rather than after the visible label; inconsistent localization of names | |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## Critical: Visible Labels Must Be Contained in the Accessible Name (WCAG 2.5.3) |
| 53 | |
| 54 | For a component with visible text or an image of text, the accessible name |
| 55 | must **contain** that visible text — having it at the *start* of the name is |
| 56 | documented best practice, not an additional normative requirement. |
| 57 | |
| 58 | ```html |
| 59 | <!-- Prefer: native text as the name --> |
| 60 | <button type="submit">Save</button> |
| 61 | |
| 62 | <!-- Wrong: accessible name is "Confirm changes", not "Save" --> |
| 63 | <button type="submit" aria-label="Confirm changes">Save</button> |
| 64 | |
| 65 | <!-- Acceptable when extra context is genuinely needed --> |
| 66 | <button type="submit" aria-label="Save document">Save</button> |
| 67 | ``` |
| 68 | |
| 69 | `aria-label`/`aria-labelledby` can override names derived from child content |
| 70 | — inspect the **computed** accessible name rather than assuming every |
| 71 | labeling source combines. Do not use placeholder text as the only label — it |
| 72 | can disappear during dictation and isn't a substitute for a programmatically |
| 73 | associated `<label>`. |
| 74 | |
| 75 | **Keep visible words contiguous and in order:** |
| 76 | |
| 77 | ```html |
| 78 | <!-- Good: visible label starts the accessible name --> |
| 79 | <button>Delete <span class="visually-hidden">quarterly report</span></button> |
| 80 | |
| 81 | <!-- Avoid: hidden words interrupt the visible label --> |
| 82 | <button aria-label="Delete the quarterly report permanently">Delete report</button> |
| 83 | ``` |
| 84 | |
| 85 | The second example contains "Delete" and "report" but inserts other words |
| 86 | between them — some speech tools m |