Version: 3.9.0 (also 3.8.0)
Both components spread the incoming props onto react-aria's Select and then set
aria-label={label ?? "Select"} after the spread:
src/lib/dropdown/select/index.tsx (lines 48-53)
src/lib/dropdown/cascader/index.tsx (lines 37-42)
So a consumer-supplied aria-label is always replaced by the literal "Select". Only
aria-labelledby survives, because it is forwarded by the spread.
Impact
Every dropdown rendered without a visible label is announced to screen readers as "Select",
regardless of what the app passes. Consumers end up writing wrappers to work around it, e.g.
web/src/components/LabeledDropdown.tsx in kleros/kleros-v2#2281, which renders a
visually-hidden span and points aria-labelledby at it.
Proposed fix
Only fall back to "Select" when nothing else labels the field, and let the spread win:
<AriaSelect
className={cn("flex flex-col gap-1", className)}
aria-label={label || props["aria-label"] || props["aria-labelledby"] ? undefined : "Select"}
{...props}
onSelectionChange={handleSelection}
>
Same change in the cascader. Alternatively, simply move the aria-label line above the
{...props} spread so consumer props take precedence.
Once released, the kleros-v2 wrapper can be deleted and callers pass aria-label directly.
Version: 3.9.0 (also 3.8.0)
Both components spread the incoming props onto react-aria's
Selectand then setaria-label={label ?? "Select"}after the spread:src/lib/dropdown/select/index.tsx(lines 48-53)src/lib/dropdown/cascader/index.tsx(lines 37-42)So a consumer-supplied
aria-labelis always replaced by the literal"Select". Onlyaria-labelledbysurvives, because it is forwarded by the spread.Impact
Every dropdown rendered without a visible
labelis announced to screen readers as "Select",regardless of what the app passes. Consumers end up writing wrappers to work around it, e.g.
web/src/components/LabeledDropdown.tsxin kleros/kleros-v2#2281, which renders avisually-hidden span and points
aria-labelledbyat it.Proposed fix
Only fall back to
"Select"when nothing else labels the field, and let the spread win:Same change in the cascader. Alternatively, simply move the
aria-labelline above the{...props}spread so consumer props take precedence.Once released, the kleros-v2 wrapper can be deleted and callers pass
aria-labeldirectly.