I have a group of radio buttons being built up from some external data, as per the examples below. They render and work as I'd expect with the exception of the aria-checked
attribute. Clicking a radio button toggles the checked value, but it remains true
when another has been selected.
If I click each radio button in sequence, I end up with a list of radio buttons that display aria-checked="true"
which obviously isn't the best experience.
I'm not sure how to go about toggling the radio buttons checked value back to false when another has been checked.
Any help would be great!
Input:
const [isChecked, setIsChecked] = useState(false);
<Input
type={type}
id={id}
value={id}
name={name}
aria-label={label}
aria-checked={isChecked}
onChange={() => setIsChecked(!isChecked)}
/>
<Label htmlFor={id}>{label}</Label>
Usage:
<fieldset>
{someData.map(item => {
return (
<RadioButton
type="radio"
key={item.id}
id={item.id}
name={item.name}
label={item.label}
/>
);
})}
</fieldset>
I have a group of radio buttons being built up from some external data, as per the examples below. They render and work as I'd expect with the exception of the aria-checked
attribute. Clicking a radio button toggles the checked value, but it remains true
when another has been selected.
If I click each radio button in sequence, I end up with a list of radio buttons that display aria-checked="true"
which obviously isn't the best experience.
I'm not sure how to go about toggling the radio buttons checked value back to false when another has been checked.
Any help would be great!
Input:
const [isChecked, setIsChecked] = useState(false);
<Input
type={type}
id={id}
value={id}
name={name}
aria-label={label}
aria-checked={isChecked}
onChange={() => setIsChecked(!isChecked)}
/>
<Label htmlFor={id}>{label}</Label>
Usage:
<fieldset>
{someData.map(item => {
return (
<RadioButton
type="radio"
key={item.id}
id={item.id}
name={item.name}
label={item.label}
/>
);
})}
</fieldset>
Share
Improve this question
asked Mar 10, 2020 at 17:48
NickNick
2,5595 gold badges39 silver badges72 bronze badges
0
2 Answers
Reset to default 4You could try something like this.
const Radio = React.memo(function Radio({
item,
checked,
onChange
}) {
console.log("rendering", item.label);
return (
<label>
{item.label}
<input
type="radio"
value={item.id}
checked={checked}
onChange={onChange}
/>
</label>
);
});
const RadioList = ({ items, value, onChange }) => (
<div>
{items.map(item => (
<Radio
item={item}
key={item.id}
checked={item.id === value}
onChange={onChange}
/>
))}
</div>
);
const App = ({ items }) => {
const [value, setValue] = React.useState(items[0].id);
const [v, setV] = React.useState(items[1].id);
const onChange = React.useCallback(
e => setValue(e.target.value),
[]
);
const onOther = React.useCallback(
e => setV(e.target.value),
[]
);
return (
<div>
<RadioList
items={items}
value={value}
onChange={onChange}
/>
<RadioList
items={items}
value={v}
onChange={onOther}
/>
</div>
);
};
//render app
ReactDOM.render(
<App
items={[
{ id: "1", label: "one" },
{ id: "2", label: "two" },
{ id: "3", label: "three" },
{ id: "4", label: "four" }
]}
/>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
There are two things you should change here.
When you are rendering a list of radio buttons under the same group, then the name attribute should be same for all the radio buttons. So instead of reading the name attribute from the
someData
, pass the same name attribute to each button. Or keep the same name insomeData
for each object.After that, I don't think the state should be on
input
ponent because once you checked the radio, you are never changing its value even after clicking on some radio button. You can try it keeping the same name attribute on each Radio button.
So the solution can be to actually pass the checked attribute to the Input ponent depending upon which radio is actually selected. Please check the following code:
const RadioButton = ({ type, id, name, label, checked, onChange }) => {
return (
<>
<input
type={type}
id={id}
value={id}
name={name}
aria-label={label}
aria-checked={checked}
checked={checked}
onChange={onChange}
/>
<label htmlFor={id}>{label}</label>
</>
)
}
const RadioGroup = () => {
const someData = [{
id: 1,
name: 'name',
label: 'name 1'
}, {
id: 2,
name: 'name',
label: 'name 2'
}, {
id: 3,
name: 'name',
label: 'name 3'
}];
const [checkedValue, setIsChecked] = useState(1);
return (
<fieldset>
{someData.map(item => {
return (
<RadioButton
type="radio"
key={item.id}
id={item.id}
name="radioGroup"
label={item.label}
checked={checkedValue === item.id}
onChange={() => setIsChecked(item.id)}
/>
);
})}
</fieldset>
)
}