Speech Recognition Accessibility Skill

SkillMedia

Load 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 let an aria-label override a visible label without keeping the visible text intact and in order. Absolutely always ensure the accessible name contains the visible label, and load alongside keyboard/SKILL.md since speech tools commonly emulate keyboard and pointer input.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Speech Recognition Accessibility Skill skill

What this skill tells your AI

The instructions your AI receives, as published by mgifford/accessibility-skills in skills/speech-recognition/SKILL.md and read by ahel’s review.

Canonical source: examples/SPEECH_RECOGNITION_ACCESSIBILITY_BEST_PRACTICES.md in mgifford/ACCESSIBILITY.md This skill is derived from that file. When in doubt, the example is authoritative.

Apply these rules when implementing or reviewing any interface that must support speech input or voice control. Load alongside keyboard/SKILL.md — speech tools often rely on keyboard and pointer emulation, so keyboard requirements are a foundation, not a substitute.


Core Mandate

Speech recognition can dictate text, navigate interfaces, activate controls, emulate keyboard input, and operate a pointer. Speech recognition is not the same as speaker recognition — speech recognition interprets words and commands; speaker recognition tries to identify who is speaking.

Core principles:

  1. Use visible, persistent labels — people must be able to determine what to say without guessing a hidden name
  2. Match visible labels and accessible names — if a control has visible text, its accessible name must contain that text
  3. Use native semantics — correct HTML names/roles/states/values/keyboard behavior give speech tools reliable information
  4. Support more than direct label activation — keyboard emulation, name/number overlays, and pointer emulation vary by product
  5. Do not require fine pointer control — provide alternatives to dragging, path gestures, and precise spatial interaction
  6. Accept input from more than key events — dictation, paste, and autocomplete may change a field without firing expected keystrokes
  7. Provide clear feedback — expose changed state, errors, confirmations, and results visually and programmatically
  8. Test the supported environments — commands, overlays, and behavior vary by product, platform, and version

Who uses speech input: people with limited movement/strength/dexterity/ reach/endurance; repetitive strain injuries, pain, tremors, or fatigue; people using speech instead of or alongside a keyboard/pointer; people with cognitive/learning disabilities who find dictation easier than typing; temporary or situational limitations; people combining speech with a screen reader, magnifier, or switch. Speech users are not necessarily sighted — do not design or test on the assumption that everyone using speech can see a label, overlay, pointer, focus indicator, or visual result.


Severity Scale (this skill)

LevelMeaning
CriticalA control cannot be activated by any speech-tool method (name, overlay, or keyboard/pointer emulation)
SeriousAccessible name doesn't contain the visible label; validation depends only on keydown and silently rejects dictated/pasted input
ModerateRepeated controls are hard to disambiguate; icon-only control has no accessible name
MinorHidden context inserted before rather than after the visible label; inconsistent localization of names

Critical: Visible Labels Must Be Contained in the Accessible Name (WCAG 2.5.3)

For a component with visible text or an image of text, the accessible name must contain that visible text — having it at the start of the name is documented best practice, not an additional normative requirement.

<!-- Prefer: native text as the name -->
<button type="submit">Save</button>

<!-- Wrong: accessible name is "Confirm changes", not "Save" -->
<button type="submit" aria-label="Confirm changes">Save</button>

<!-- Acceptable when extra context is genuinely needed -->
<button type="submit" aria-label="Save document">Save</button>

aria-label/aria-labelledby can override names derived from child content — inspect the computed accessible name rather than assuming every labeling source combines. Do not use placeholder text as the only label — it can disappear during dictation and isn't a substitute for a programmatically associated <label>.

Keep visible words contiguous and in order:

<!-- Good: visible label starts the accessible name -->
<button>Delete <span class="visually-hidden">quarterly report</span></button>

<!-- Avoid: hidden words interrupt the visible label -->
<button aria-label="Delete the quarterly report permanently">Delete report</button>

The second example contains "Delete" and "report" but inserts other words between them — some speech tools may not match the phrase a user sees. A hidden prefix (context appearing before the visible word) is not automatically a 2.5.3 failure if the visible text still appears intact, but it can still make direct label activation harder — prefer not to put hidden words before the text a person sees. Put format hints/constraints in an aria-describedby description, not the name.


Serious: Disambiguate Repeated Controls Without Renaming Them

Repeated labels ("Edit", "Delete", "Read more") can cause a speech tool to present several matches — not automatically a conformance failure, but it increases effort. Prefer specific visible labels when concise:

<a href="/services">Read about services</a>
<a href="/products">Read about products</a>

For compact repeated actions, add contextual text after the visible action:

<li>
  Billing address
  <a href="/account/billing/edit">Edit <span class="visually-hidden">billing address</span></a>
</li>

Do not make accessible names unique by replacing or reordering the visible label — "Modify billing address" is not a good hidden name for a visible "Edit" link.


Moderate: Icon-Only Controls

Still need an accessible name under WCAG 4.1.2 (2.5.3 doesn't apply when there's no visible text label):

<button type="button" aria-label="Close dialog">
  <svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
    <path d="M6 6 18 18M18 6 6 18"></path>
  </svg>
</button>

Persistent visible text is usually more discoverable than an icon alone. A tooltip appearing only on hover/focus is not a persistent visible label — a person must first discover or target the control before it helps. If an icon-only design is retained: use a concise localized name; use a familiar icon consistently; provide adequate target size/spacing; ensure name/number overlays identify it; don't use color or position as the only description; test with the supported speech tools.


Critical: Native Semantics and Keyboard Operation

Speech tools often use accessibility APIs, keyboard emulation, or pointer emulation — native HTML supplies reliable role/name/state/value/focus/ activation behavior for free.

<!-- Wrong: not a reliable button -->
<div class="button" onclick="saveDocument()">Save</div>

<!-- Correct -->
<button type="button" onclick="saveDocument()">Save</button>

Do not publish tables claiming a particular spoken phrase always works for every role — command grammar differs by speech product, platform, locale, and version. Correct semantics still improve compatibility and remain required for other AT. All functionality must be available through a keyboard interface (unless the function requires path-dependent input) — speech software can use that keyboard interface as one operating method. For custom widgets: use the correct role only when no native element suffices; implement the expected keyboard interaction; expose name/state/properties/ value; update programmatic state when visual state changes; follow an established APG pattern. See skills/keyboard/SKILL.md.


Serious: Dictation and Text Entry Must Not Depend Only on keydown

Speech dictation may insert, replace, or delete text without producing the same keydown sequence as a physical keyboard.

// Correct: responds to value changes regardless of input method
search.addEventListener('input', () => updateSuggestions(search.value));

// Wrong: dictation, paste, and autocomplete may bypass this logic
search.addEventListener('keydown', event => updateSuggestions(event.key));

Text-entry controls should: use native inputs/textareas; have persistent visible labels; expose format instructions and errors programmatically; accept paste, dictation, autocomplete, and programmatic value changes; allow editing/correction before submission; avoid short time limits or speech-rate assumptions; not require a specific punctuation phrase when another valid value is acceptable; preserve entered content after validation errors. Do not infer that a lack of keydown means no input occurred — validate the current value at the appropriate event and again at submission.


Serious: Dragging, Gestures, and Spatial Interaction Need Direct Alternatives

Dragging with a speech-controlled pointer can require several commands and precise timing.

<!-- Reordering alternative -->
<li>
  Budget report
  <button type="button">Move up <span class="visually-hidden">Budget report</span></button>
  <button type="button">Move down <span class="visually-hidden">Budget report</span></button>
</li>

If drag-and-drop is also available, both methods should update the same model and provide confirmation. For sliders, pair the draggable control with a direct entry or step control:

<label for="volume">Volume</label>
<input id="volume" type="range" min="0" max="100" value="50">
<label for="volume-value">Volume percentage</label>
<input id="volume-value" type="number" min="0" max="100" value="50">

WCAG 2.5.7 requires author-created dragging to have a single-pointer alternative unless essential — a keyboard-only alternative does not necessarily satisfy this single-pointer requirement. Path-based or multipoint gestures need a single-pointer alternative under 2.5.1 too, unless the gesture is essential. See skills/touch-pointer/SKILL.md.


Moderate: Focus, Scrolling, and Overlays

Some speech users emulate keyboard commands or combine speech with another input method — focus order, visibility, and unobscured controls remain important. Sticky headers/cookie notices/chat launchers must not hide a focused component (WCAG 2.4.11).

html { scroll-padding-block-start: var(--sticky-header-height, 4rem); }
:focus-visible { scroll-margin-block: 0.5rem; }

Ensure: focus doesn't move behind an open modal; closing a dialog returns focus to a logical control; direct activation scrolls the target into view when needed; overlays can be dismissed without dragging or precise pointer movement; no essential control is permanently covered at supported viewport sizes. Speech input can be combined with a screen reader, so interaction must not depend on seeing focus or an overlay.


Serious: Expose State, Results, and Error Feedback Programmatically

<button type="button" aria-expanded="false" aria-controls="filters-panel">Filters</button>
<div id="filters-panel" hidden><!-- Filter controls --></div>

Update both aria-expanded and hidden together — similarly for aria-pressed, aria-checked, selected tabs, and slider values.

<p id="cart-status" role="status" aria-atomic="true"></p>

Use visible text and an appropriate status-message pattern (see skills/aria-live-regions/SKILL.md) — don't move focus for every confirmation. For errors needing immediate correction, associate the error with the field and use the form's established error-summary strategy. Avoid feedback that is: shown only by color/animation/icon change; available only on hover; removed before it can be perceived; announced repeatedly for every dictated character; hidden from accessibility APIs; disconnected from the control that caused it.


Moderate: Labels, Symbols, and Localization

Use the same human language for visible labels and accessible names — translate aria-label, hidden context, descriptions, and error messages with the rest of the interface. Do not normalize every symbol into an unrelated word — the correct name depends on function: a magnifying-glass icon used as a control is named "Search," not "Magnifying glass"; a visible X used only as a close icon should have the function "Close." Test speech matching in each supported interface and dictation language — a command working in English may not work after translation.


Product and Platform Variation

Speech tools differ in how they activate a control by name, display name/ number/grid overlays, disambiguate repeated names, emulate keyboard/pointer input, handle embedded frames and shadow DOM, and switch between command/dictation modes. Do not put fixed command phrases, product versions, or compatibility claims into a project standard unless the project actively maintains and retests them.

Record the actual test environment:

Speech input product and version:
Operating system and version:
Browser and version:
Input and interface language:
Command, dictation, or mixed mode:
Viewport, zoom, and text size:

Testing

  • Static inspection: identify the visible label; inspect the computed accessible name/role; confirm visible words occur intact and in order in the name; check for hidden text before or inside the visible phrase; verify state/value/description relationships; confirm repeated controls can be distinguished; verify icon-only controls have concise names; verify names and hidden text are translated. Inspect the computed accessibility tree — don't infer the final name by reading attributes independently.
  • Keyboard foundation (without a pointer): reach and operate all functionality; follow a logical focus order; open/use/close custom widgets; escape dialogs/menus/popovers; confirm focus stays visible and unobscured; complete drag alternatives.
  • Speech input test (per supported environment): activate visibly labeled controls by speaking the visible label using the tool's documented grammar; inspect the tool's name/number overlay for discoverability; distinguish repeated controls; operate icon-only controls and custom widgets; dictate/edit/replace/submit text; trigger and correct validation errors; navigate modals/menus/tabs/disclosures/ autocomplete; complete sorting/reordering/slider/map/canvas tasks through alternatives; confirm state changes and status feedback; repeat critical tasks after zoom/reflow/localization changes. Do not require every control to respond to one literal phrase like "Click [label]" — use the tested tool's documented grammar.
  • Test with users who regularly use speech input — a technical pass cannot reveal the full effort of correcting recognition errors, disambiguating controls, or navigating a dense overlay.

Automated checks can detect controls without accessible names, some visible-label-in-name mismatches, invalid/missing roles/states, click handlers on non-interactive elements, and duplicate accessible names — cannot determine whether a speech product actually recognizes a label, whether repeated controls are practically distinguishable, or whether the total number of commands makes a task unreasonably difficult. Treat uncertain automated results as review items, not confirmed failures.


Common Failures

FailureCorrection
Visible "Save" button has hidden name "Confirm changes"Use "Save," or a name beginning with "Save"
Hidden words inserted inside the visible phraseKeep visible words contiguous and in order
Every repeated link is visibly "Read more"Use specific visible text or append contextual hidden text after it
Placeholder is the only field labelAdd a persistent, associated <label>
Icon-only button has no accessible nameAdd a concise name; prefer persistent visible text
Tooltip treated as a visible labelKeep the label persistently visible when discoverability matters
Styled <div> acts as a buttonUse <button> or implement the complete custom-widget contract
Validation runs only on keydownRespond to input, current values, and submission
Reordering requires drag and drop onlyAdd Move up/Move down or position controls
Gesture is the only way to operate a featureAdd simple controls for the same result
Sticky content hides the focused controlAdjust layout/scrolling; test at supported sizes
State changes only visuallyUpdate programmatic state and provide visible feedback
Project documentation promises universal spoken commandsTest and document the actual supported products and locales
Testing assumes every speech user can seeInclude non-visual and combined AT use

Definition of Done Checklist

  • Every control exposes an accurate name, role, state, and value
  • Every visible text label is contained intact and in order in the accessible name
  • Visible text appears at the start of the accessible name where practical
  • Native HTML used where it can provide the required control
  • Custom controls follow supported keyboard and ARIA patterns
  • Repeated controls can be distinguished efficiently without renaming them
  • Icon-only controls have concise, localized accessible names
  • Form fields have visible, programmatically associated labels (not placeholder-only)
  • Dictation, paste, autocomplete, editing, and correction update fields correctly
  • Validation does not depend only on physical key events
  • All functionality available through a keyboard interface
  • Dragging and path-based gestures have single-pointer alternatives
  • Focus remains logical, visible, and unobscured
  • States, validation errors, confirmations, and results exposed programmatically
  • Critical tasks tested in supported speech products, browsers, and languages
  • Automated results supplemented by manual speech-input testing

Key WCAG Criteria

  • 1.3.1 Info and Relationships (A)
  • 2.1.1 Keyboard (A)
  • 2.4.3 Focus Order (A)
  • 2.4.7 Focus Visible (AA)
  • 2.4.11 Focus Not Obscured Minimum (AA)
  • 2.5.1 Pointer Gestures (A)
  • 2.5.3 Label in Name (A) — Serious if visible label not contained in accessible name
  • 2.5.7 Dragging Movements (AA)
  • 3.3.2 Labels or Instructions (A)
  • 4.1.2 Name, Role, Value (A)
  • 4.1.3 Status Messages (AA)

WCAG criteria describe outcomes, not product-specific spoken commands — a command failing in one environment may indicate a content defect, a product limitation, a localization issue, or an unsupported combination. Record the environment and investigate before assigning a standards failure.


References

Standards horizon: These rules target WCAG 2.2 AA. Monitor: https://www.w3.org/TR/wcag-3.0/

Signals

GitHub stars
44
Forks
2
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
speech-recognition-mgifford
Source
github.com/mgifford/accessibility-skills