docs: hide placeholder select options from assistive tech - #42739
docs: hide placeholder select options from assistive tech#42739Hashim1999164 wants to merge 1 commit into
Conversation
Add aria-hidden="true" to default placeholder options in form docs so screen readers do not vocalize hint text when focus enters a select. Fixes twbs#37614
Greptile SummaryThis PR adds
Confidence Score: 3/5Not safe to merge as-is — the change propagates a pattern that may silently fail on major screen readers, and actively introduces an accessibility inconsistency in expanded listbox selects. The multiple and size select examples in select.mdx now hide a visible, navigable option from AT while keeping it selectable for mouse/sighted users. Across all files, the fix relies on aria-hidden propagating through OS-level accessibility APIs for native select controls, which is not guaranteed on Windows screen readers. The validation examples add aria-hidden to the currently-selected option, risking suppression of value announcements if browsers do honor the attribute. select.mdx (multiple and size select examples), validation.mdx (selected+disabled placeholder options), and floating-labels.mdx all need a second look before merging. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Select element receives AT focus] --> B{Select type?}
B -->|Standard dropdown| C[Select collapsed - AT announces label + current value]
B -->|multiple or size select| D[Listbox always expanded - all options visible]
C --> E{aria-hidden on selected option?}
D --> F[User navigates options with arrow keys]
E -->|No - baseline| G[AT announces current option text normally]
E -->|Yes - this PR| H{Browser honors aria-hidden on option?}
H -->|Yes - ARIA tree path| I[AT skips option - current value silent]
H -->|No - OS API path| J[aria-hidden ignored - AT still announces option]
F --> K[Option visible but silent to AT]
K --> L[WCAG 1.3.1 concern: info available visually but not to AT]
|
| Custom `<select>` menus need only a custom class, `.form-select` to trigger the custom styles. Custom styles are limited to the `<select>`’s initial appearance and cannot modify the `<option>`s due to browser limitations. | ||
|
|
||
| <Example code={`<select class="form-select" aria-label="Default select example"> | ||
| <option selected>Open this select menu</option> | ||
| <option selected aria-hidden="true">Open this select menu</option> | ||
| <option value="1">One</option> | ||
| <option value="2">Two</option> |
There was a problem hiding this comment.
aria-hidden on <option> has inconsistent AT support
Screen readers on Windows (NVDA, JAWS) traditionally access native <select> elements through OS-level accessibility APIs (IAccessible2/UIA) rather than the ARIA accessibility tree. The degree to which those APIs propagate aria-hidden on individual <option> children varies by browser/AT pairing. There's real risk that the attribute is silently ignored by major screen readers in practice, leaving the documentation teaching a pattern that may not behave as described. A more broadly supported technique for a non-selectable placeholder is disabled hidden value="" on the <option>, which signals non-selectability at the HTML level rather than relying on ARIA propagation through a native OS widget. This applies across every changed file in this PR.
There was a problem hiding this comment.
Fair point on the uneven AT support. The intent here is only to stop the placeholder from being read out as a real choice in the options list; visual rendering is unchanged. If the team prefers, I can scope this down to the select.mdx examples only, or drop it entirely in favor of documenting the disabled+hidden placeholder pattern instead. Happy to go either way.
| <div class="col-md-3"> | ||
| <label for="validationCustom04" class="form-label">State</label> | ||
| <select class="form-select" id="validationCustom04" required> | ||
| <option selected disabled value="">Choose...</option> | ||
| <option selected disabled value="" aria-hidden="true">Choose...</option> | ||
| <option>...</option> |
There was a problem hiding this comment.
aria-hidden on the currently-selected option may suppress value announcement
In these validation examples the placeholder option is both selected and the current value of the control. When AT focuses the <select>, it typically announces the currently selected option text. If that option is aria-hidden="true" and the browser does propagate the attribute, AT would have nothing to announce as the current value — users would know they're on a select control but not what it currently says. The disabled value="" already present on these options communicates non-selectability at the HTML level; the additional aria-hidden is both redundant and potentially harmful to the value-announcement flow.
There was a problem hiding this comment.
This one is the stronger concern, since the placeholder is also the current value here and hiding it could leave the control announcing nothing on focus. I can revert the validation.mdx changes so aria-hidden is only used where the placeholder is not the selected value, if that is the direction the team wants.
Summary
aria-hidden="true"to default placeholder<option>elements in form documentation examples.Motivation
When a select receives focus, assistive technologies can vocalize the placeholder option text (for example, "Open this select menu") even though the visible
<label>oraria-labelalready describes the control. Hiding placeholder options from the accessibility tree avoids redundant announcements.Fixes #37614
Test plan
aria-hidden="true"