JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.63k stars 4.13k forks source link

Placeholder linked to Input through aria-describedby #5651

Open socproof opened 1 year ago

socproof commented 1 year ago

Placeholder and Input from react-select are linked not via label, aria-label or aria-labeledby, but through aria-describedby - which is absolutely incorrect.

Raw HTML from https://react-select.com/home examples

<div id="react-select-11-placeholder">Select...</div>
<div>
<input class="" autocapitalize="none" autocomplete="off" autocorrect="off" id="react-select-11-input" spellcheck="false" tabindex="0" type="text" aria-autocomplete="list" aria-expanded="false" aria-haspopup="true" role="combobox" aria-describedby="react-select-11-placeholder">
</div>

See the difference:

I believe the current implementation should be redone to make Placeholder linked to Input via aria-labeledby

wbolduc commented 1 year ago

I don't think that using aria-labelledby is the correct choice either here because it has the highest priority as an accessible name overriding the name given by a label for="input-id"

I would prefer using aria-placeholder if the placeholder is ALWAYS plaintext or aria-describedby

There is still a problem though in the current implementation where aria-describedby isn't being respected. To get around this you can use the following custom input

const Input = (props: InputProps) => {
    const passed_describedby = props.selectProps["aria-describedby"];
    const describedby =
        props["aria-describedby"] +
        (passed_describedby ? " " + passed_describedby : "");
    return <components.Input {...props} aria-describedby={describedby} />;
};

Which you can plug into your Select with

<ReactSelect
    components={{
        Input,
    }}
/>

This works okay because describedby accepts multiple ids. If you are using describedby to identify your errors your resolved description ends up looking like this "Select... Required" Which I think is okay