Using mui to create a radio button within a button and it should be possible to click on either the radio button or the button, when clicking on either of them the radio has to be checked. Only one option can be chosen, either female or male.
I know I could use multiple use states for clicked, but isn't there some better way to do it?
import FormControl from '#mui/material/FormControl';
import FormLabel from '#mui/material/FormLabel';
import RadioGroup from '#mui/material/RadioGroup';
import FormControlLabel from '#mui/material/FormControlLabel';
import Button from '#mui/material/Button';
import Radio from '#mui/material/Radio';
export const radioButtonGroup = () => {
const [value, setValue] = React.useState('female');
const [clicked, setClicked] = useState(false);
return (
<FormControl>
<FormLabel>Gender</FormLabel>
<RadioGroup value={value}>
<Button
onClick={() => setClicked(true)}
variant="outlined">
<FormControlLabel
value="female"
control={<Radio checked={clicked} />}
label="Female" />
</Button>
<Button
onClick={() => setClicked(true)}
variant="outlined">
<FormControlLabel
value="male"
control={<Radio checked={clicked} />}
label="Male" />
</Button>
</RadioGroup>
</FormControl>
);
};
Looks like this:
export const radioButtonGroup = () => {
const [gender, setGender] = useState('');
return (
<FormControl>
<FormLabel>Gender</FormLabel>
<RadioGroup>
<Button
onClick={() => setGender('female')}
variant="outlined">
<FormControlLabel
control={<Radio checked={gender === 'female'} />}
label="Female" />
</Button>
<Button
onClick={() => setGender('male')}
variant="outlined">
<FormControlLabel
control={<Radio checked={gender === 'male'} />}
label="Male" />
</Button>
</RadioGroup>
</FormControl>
);
};
Related
How can I write a react testing library test script to validate clicking on a Material UI radio button? The below is a recreation of the issue I am having.
import React from 'react';
import Radio from '#material-ui/core/Radio';
import RadioGroup from '#material-ui/core/RadioGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
import FormLabel from '#material-ui/core/FormLabel';
export default function RadioButtonsGroup() {
const [value, setValue] = React.useState('female');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<FormControl component="fieldset">
<FormLabel component="legend">Gender</FormLabel>
<RadioGroup aria-label="gender" name="gender1" value={value} onChange={handleChange}>
<FormControlLabel value="female" control={<Radio />} label="Female" />
<FormControlLabel value="male" control={<Radio />} label="Male" />
<FormControlLabel value="other" control={<Radio />} label="Other" />
<FormControlLabel value="disabled" disabled control={<Radio />} label="(Disabled option)" />
</RadioGroup>
</FormControl>
);
}
and the test
import { render, screen, fireEvent } from "#testing-library/react";
import RadioButtonsGroup from "./demo";
test("can click Male radio option", () => {
render(<RadioButtonsGroup />);
const maleLabel = screen.getByLabelText(/Male/);
fireEvent.click(maleLabel);
expect(maleLabel).toBeChecked();
});
Hey – get by role should help you here. Try:
const button = screen.getByRole("radio", { name: "Male" });
This should give you access to the radio button with the lable as Male.
Then you can do
const leftClick = { button: 0 };
userEvent.click(button, leftClick);
expect(button.checked).toBe(true);
One thing I've found though is that the .checked property doesn't play nice with Typescript so if you're writing typescript, you may get warnings about .checked being non-existent
I'm going to make checkbox and select fields with Material UI. However, I don't how to handle on change event. The dropdown isn't selected if I selected one item of list, and clicking the checkbox isn't checked.
Here is the code:
import React from "react";
import { useForm, useFieldArray } from "react-hook-form";
import {
FormControlLabel,
FormLabel,
FormGroup,
FormControl,
Button,
Box,
MenuItem,
Select,
Checkbox
} from "#material-ui/core";
import "./styles.css";
export default function App() {
const { register, setValue, control } = useForm({
defaultValues: {
infoGp: [
{
title: "",
restricted: false,
prohibited: false,
bus: false,
close: false
}
]
},
mode: "onBlur"
});
const { fields, append, remove } = useFieldArray({
control,
name: "infoGp"
});
const handleAddItem = () => {
append({
title: "",
restricted: false,
prohibited: false,
bus: false,
close: false
});
};
return (
<div className="App">
{fields.map((item, index) => {
return (
<Box border={1} p={3}>
<Box mb={4}>
<FormControl>
<Select
name={`infoGp${index}.title`}
value={`${item.title}`}
// onChange={titleChange}
displayEmpty
ref={register}
>
<MenuItem value="">Title</MenuItem>
<MenuItem value="mr">Mr.</MenuItem>
<MenuItem value="mrs">Mrs.</MenuItem>
<MenuItem value="miss">Miss</MenuItem>
</Select>
</FormControl>
</Box>
<Box>
<FormControl component="fieldset">
<FormLabel component="legend">Type of Location</FormLabel>
<FormGroup className="permitType">
<FormControlLabel
control={
<Checkbox
checked={item.restricted}
inputRef={register}
// onChange={permitTypeChange}
name={`infoGp${index}.restricted`}
/>
}
label="restricted"
/>
<FormControlLabel
control={
<Checkbox
checked={item.prohibited}
inputRef={register}
// onChange={permitTypeChange}
name={`infoGp${index}.prohibited`}
/>
}
label="prohibited"
/>
<FormControlLabel
control={
<Checkbox
checked={item.bus}
inputRef={register}
// onChange={permitTypeChange}
name={`infoGp${index}.bus`}
/>
}
label="bus stop"
/>
<FormControlLabel
control={
<Checkbox
checked={item.close}
inputRef={register}
// onChange={permitTypeChange}
name={`infoGp${index}.close`}
/>
}
label="close zone"
/>
</FormGroup>
</FormControl>
</Box>
{index > 0 && (
<Button
variant="contained"
color="secondary"
onClick={() => remove(index)}
>
remove
</Button>
)}
</Box>
);
})}
<Box mt={5}>
<Button variant="contained" color="primary" onClick={handleAddItem}>
add item
</Button>
</Box>
</div>
);
}
Should I use setValues or setState to handle onChange?
codesandbox here:
https://codesandbox.io/s/react-hook-form-field-array-on-checkbox-select-g6gq9?file=/src/App.js:0-3872
You can use Controller and control for the checkbox in react-hook-form version 7.
Here is an example:
https://codesandbox.io/s/rhf-controller-material-ui-9ik00?file=/src/App.js
I have a minimalist function whereby I'm providing two choices in the form of radio inputs: "bull" or "bear".
Full code below:
import React, { useState } from 'react';
import RadioButton from 'material-ui/RadioButton';
const styles = {
rootRadio: {
//left:"37%",
//position:'absolute'
}
}
function RadioComp() {
const [riskP, setRiskP] = useState("bull")
const handleRisk = (e) => {
setRiskP(e.target.value)
}
return (
<React.Fragment>
<h2>Risk profile</h2>
<div>
<span>Bull</span>
<RadioButton
style={styles.rootRadio}
value='bull'
checked={riskP==='bull'}
onChange={handleRisk}
/>
</div>
<div>
<span>Bear</span>
<RadioButton
style={styles.rootRadio}
value='bear'
checked={riskP==='bear'}
onChange={handleRisk}
/>
</div>
</React.Fragment>
)
}
export default RadioComp;
As seen above, I have tried to configure this logic using useState():
const [riskP, setRiskP] = useState("bull")
const handleRisk = (e) => {
setRiskP(e.target.value)
}
However, in the view, clicking on "bear" doesn't do anything. It seems to be locked on "bull."
Question
You have to use RadioGroup with FormControl option.
import React from 'react';
import Radio from '#material-ui/core/Radio';
import RadioGroup from '#material-ui/core/RadioGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
import FormLabel from '#material-ui/core/FormLabel';
export default function RadioButtonsGroup() {
const [value, setValue] = React.useState('female');
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<FormControl component="fieldset">
<FormLabel component="legend">Gender</FormLabel>
<RadioGroup name="gender1" value={value} onChange={handleChange}>
<FormControlLabel value="female" control={<Radio />} label="Female" />
<FormControlLabel value="male" control={<Radio />} label="Male" />
<FormControlLabel value="other" control={<Radio />} label="Other" />
</RadioGroup>
</FormControl>
);
}
I am trying to use a custom Radio component with React-final-form but it is not acting as a radio button but as a checkbox, ie, all the buttons are open for selection.
The 3rd party Radio button has the following schema:
checked boolean
Whether or not radio is checked
onChange () => void
Called when the user attempts to change the checked state
name string
The input name, used to reference the element in JavaScript
I created a custom Component for using the Radio Component:
const CustomRadio = (props: any) => (
<Radio
{...props.input}
{...props.rest}
name={props.name}
onChange={() => props.input.onChange()}
/>
)
and I am using it as follows:
<Field name="food"
component={CustomRadio}
value="1"
/>
<Field name="food"
component={CustomRadio}
value="2"
/>
Being very new to RFF and new to React, I may be doing something very wrong, hence any help will be appreciated.
Basically, I want to use RFF with my 3rd party components. Though I have been successful to use my Input component with RFF as expected, Radio Button is the one creating problems.
Here is the correct implementation for Radio with react-final-form:-
https://codesandbox.io/s/vibrant-easley-5n1ek?file=/index.js
/* eslint-disable jsx-a11y/accessible-emoji */
import React from "react";
import { render } from "react-dom";
import Styles from "./Styles";
import { Form, Field } from "react-final-form";
import RadioGroup from "#material-ui/core/RadioGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import FormControl from "#material-ui/core/FormControl";
import Radio from "#material-ui/core/Radio";
import FormLabel from "#material-ui/core/FormLabel";
const RadioWrapper = (props) => {
const {
input: { checked, value, name, onChange, ...restInput },
} = props;
return (
<Radio
name={name}
inputProps={restInput}
onChange={onChange}
checked={checked}
value={value}
/>
);
};
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const onSubmit = async (values) => {
await sleep(300);
window.alert(JSON.stringify(values, 0, 2));
};
const App = () => {
return (
<Styles>
<h1>React Final Form - Simple Example</h1>
<a
href="https://final-form.org/react"
target="_blank"
rel="noopener noreferrer"
>
Read Docs
</a>
<Form
onSubmit={onSubmit}
initialValues={{
employed: false,
all_sub_tenants: "true"
}}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<FormControl component="fieldset">
<FormLabel component="legend">
Select Tenants
</FormLabel>
<RadioGroup aria-label="allSubTenants" name="allSubTenants">
<FormControlLabel
value="true"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"true"}
/>
}
label="All Sub-Tenants"
/>
<FormControlLabel
value="false"
control={
<Field
name="all_sub_tenants"
component={RadioWrapper}
type="radio"
value={"false"}
/>
}
label="Select Sub-Tenants"
/>
</RadioGroup>
</FormControl>
<div>
<label>Notes</label>
<Field name="notes" component="textarea" placeholder="Notes" />
</div>
<div className="buttons">
<button type="submit" disabled={submitting || pristine}>
Submit
</button>
<button
type="button"
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</button>
</div>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
</Styles>
);
};
render(<App />, document.getElementById("root"));
I wish to be able to uncheck radio buttons, Idea is like this: if I click on some radio button, it is going to be checked, if I click on another field, this another field is going to be checked instead BUT if I click on field which is already checked, I wish to uncheck it so all fields are empty. I tried to catch the moment of being checked or unchecked but seems like opposite to checkboxes, Radio buttons don't have this field. does anyone has idea how to achieve that?
setTests = (key, e) => {
console.log(e.checked)
if (e.checked) {
// this.setState({[key]: null})
console.log('works')
}
}
RadioGroup
value={this.state.test_mode}
style={{ display: "block" }}
onChange={e => this.setTests({ "test_mode", e.target })}
>
<FormControlLabel value="before" control={<Radio color="primary"/>} label="before tests" />
<FormControlLabel value="progressing" control={<Radio color="primary"/>} label="progressing" />
<FormControlLabel value="done" control={<Radio color="primary"/>} label="done" />
</RadioGroup>
Below is an example of how to do this. Instead of using the onChange of the RadioGroup, you use the onClick event of the Radio. If the new value matches the current value in state, then set the value to empty string.
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Radio from "#material-ui/core/Radio";
import RadioGroup from "#material-ui/core/RadioGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import FormControl from "#material-ui/core/FormControl";
import FormLabel from "#material-ui/core/FormLabel";
const useStyles = makeStyles(theme => ({
root: {
display: "flex"
},
formControl: {
margin: theme.spacing(3)
},
group: {
margin: theme.spacing(1, 0)
}
}));
export default function RadioButtonsGroup() {
const classes = useStyles();
const [value, setValue] = React.useState("female");
function handleClick(event) {
if (event.target.value === value) {
setValue("");
} else {
setValue(event.target.value);
}
}
return (
<div className={classes.root}>
<FormControl component="fieldset" className={classes.formControl}>
<FormLabel component="legend">Gender</FormLabel>
<RadioGroup
aria-label="gender"
name="gender1"
className={classes.group}
value={value}
>
<FormControlLabel
value="female"
control={<Radio onClick={handleClick} />}
label="Female"
/>
<FormControlLabel
value="male"
control={<Radio onClick={handleClick} />}
label="Male"
/>
<FormControlLabel
value="other"
control={<Radio onClick={handleClick} />}
label="Other"
/>
</RadioGroup>
</FormControl>
</div>
);
}