Version: 3.9.0 — src/lib/form/custom-radio.tsx (and radio-group.tsx)
Some groups need to be clearable by pressing the selected option again. kleros-v2's dispute feature selection is one:
choosing a feature disables incompatible features in the other group, so users must be able to undo a choice
without a separate control (kleros/kleros-v2#2281, web/src/components/DisputeFeatures/Features/FeatureRadio.tsx).
There is no supported way to do this from a consumer today:
- The library bundles its own react-aria; its
useRadio reads only value, children, aria-label,
aria-labelledby, so onPress/onPressStart on CustomRadioItem are ignored.
- The label press selects in the click bubble phase and stops propagation, and the consumer's own
RadioGroupStateContext (from its react-aria-components) is a different module instance.
- What works is a capture-phase click/keyup handler that defers the clear with
setTimeout(0) so it lands after
react-aria's press. It is a timing workaround, and a test in jsdom cannot even detect when it breaks.
Proposal: allowDeselect?: boolean on CustomRadio (and Radio). Inside the group, intercept the press on an
item whose value === state.selectedValue and call state.setSelectedValue(null) (react-aria's
RadioGroupState.setSelectedValue accepts null), so onChange(null) reaches the consumer. Space on the selected
item should behave the same. Radios are not normally deselectable, so an explicit opt-in keeps the default semantics.
Version: 3.9.0 —
src/lib/form/custom-radio.tsx(andradio-group.tsx)Some groups need to be clearable by pressing the selected option again. kleros-v2's dispute feature selection is one:
choosing a feature disables incompatible features in the other group, so users must be able to undo a choice
without a separate control (kleros/kleros-v2#2281,
web/src/components/DisputeFeatures/Features/FeatureRadio.tsx).There is no supported way to do this from a consumer today:
useRadioreads onlyvalue,children,aria-label,aria-labelledby, soonPress/onPressStartonCustomRadioItemare ignored.RadioGroupStateContext(from its react-aria-components) is a different module instance.setTimeout(0)so it lands afterreact-aria's press. It is a timing workaround, and a test in jsdom cannot even detect when it breaks.
Proposal:
allowDeselect?: booleanonCustomRadio(andRadio). Inside the group, intercept the press on anitem whose
value === state.selectedValueand callstate.setSelectedValue(null)(react-aria'sRadioGroupState.setSelectedValueacceptsnull), soonChange(null)reaches the consumer. Space on the selecteditem should behave the same. Radios are not normally deselectable, so an explicit opt-in keeps the default semantics.