JedWatson / JedWatson/react-select
Screen reader issues when trying to add a label to react select
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 28k
- Forks
- 4.1k
- PR merge metrics
- No merged PRs in 30d
Description
I ran into issues trying to properly add an accessible label to the react-select element on my Form component.
I added react select without a label element and my Chrome aXe dev tools extension flagged it as missing a name (4.1.2).
The docs on your site say to wrap react select in a label element so I did that and now the Voice Over screen reader (MAC) is over announcing information that isn't helpful. aXe is now happy, but the user now has a worse experience than before.
To resolve this issue, I had to find the id value on react select's role="combobox" input and set the for value of the label element to use that value instead of wrapping your component in a label as instructed. Now Voice Over reads as expected.
I tried doing what I though would be the easiest approach by populate the id prop on react select, but that didn't place the id on the input and instead set it on a wrapping div, which wasn't helpful. Would it be possible to either pass a label value into react select to properly setup the label or to pass in an ID that can be added to the input so I can properly setup and external label?
For Reference, this is the final code that I'm using to resolve the issue.
import Select from "react-select";
const SelectApp = (props) => {
const { options, name, label, placeholder } = props;
const [selectId, setSelectId] = useState("");
const inputRef = useRef();
const selectRef = useRef();
useEffect(() => {
// get the id from the react-select input to meet WCAG requirements.
// wrapping react-select in a label broke the screen reader.
const input = selectRef.current?.querySelector("input");
if (input?.id) {
setSelectId(input.id);
}
}, [selectRef]);
// store the selected value in an input so it can be submitted with the form.
const handleChange = (selectedOption) => {
inputRef.current.value = selectedOption.value;
};
return (
<>
<label className="select__label" htmlFor={selectId}>
{label}
</label>
<input ref={inputRef} name={name} type="hidden" />
<div className="select__input" ref={selectRef}>
<Select
options={options}
onChange={handleChange}
placeholder={placeholder}
/>
</div>
</>
);
};
SelectApp.propTypes = propTypes;
export default SelectApp;
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by inspecting the react-select component's handling of the id prop and the input rendered with role="combobox", then review the accessibility documentation describing label usage. The change is complete when an external label can correctly target the input and VoiceOver no longer over-announces the select while automated accessibility checks remain satisfied.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react
- Domain
- accessibility, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100