JedWatson / JedWatson/react-select

Screen reader issues when trying to add a label to react select

Open
#5,992 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

issue/bug-unconfirmed
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).
image

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.

image

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.

image

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.