The MUI RadioGroup is a specialized component for wrapping radio buttons and controlling alignment. As we will see later, it renders the same as a FormGroup except with role="radiogroup"
.
Here’s the example we will build in this tutorial:

This RadioGroup has an onChange handler and can be given error and disabled states through its parent FormControl. My RadioGroup has a default value and is horizontally aligning its children Radio buttons.
MUI RadioGroup Horizontal
RadioGroup is similar to FormGroup. The two primary features of RadioGroup are layout control and semantic markup.
The RadioGroup has display: flex
applied by default because it has class MuiFormGroup-root
applied. There is no MuiRadioGroup-root class.
The RadioGroup is used so often for layout that it has a built-in prop named row
for determining flex direction:
<RadioGroup row />
The row
prop sets flex direction to row
, while the default flex direction is column
.
We’ll discuss the semantic meaning in the Styling section.
MUI RadioGroup onChange
RadioGroup detects changes in child radio buttons and fires a change event. Use the onChange
prop to handle the change event:
const disabledText = "DISABLED";
const errorText = "ERROR";
const clearText = "NONE";
export default function RadioGroupExample() {
const [state, setState] = useState(clearText);
const handleRadioChange = (event: React.ChangeEvent<HTMLInputElement>, value: string) => {
setState(value);
}
return (
<RadioGroup onChange={handleRadioChange }>
<FormControlLabel
value={errorText}
control={<Radio />}
label="Set ERROR"
/>
<FormControlLabel
value={disabledText}
control={<Radio />}
label="Set DISABLED"
/>
<FormControlLabel
value={clearText}
control={<Radio />}
label="Set NONE"
/>
</RadioGroup>
)
}
RadioGroup onChange
passes an event and value by default. The value comes from the child Radio that was selected.
In my demo I created three constants for state and use these as the values on the Radios. In the handler I simply set React useState hook with the Radio value.
RadioGroup onChange is similar to the MUI Switch onChange handler.
MUI RadioGroup Default Value
The default value can quickly be set using the defaultValue
prop.
<RadioGroup defaultValue={clearText}/>
Make sure you don’t assign a state value to the defaultValue or you may see warnings in the DOM when the state changes. A default value should not change.
The default value trickles down to children Radios and auto-selects the Radio with a matching value.
In my demo the third Radio (“Set NONE”) is selected by default.

MUI RadioGroup Error
Interestingly, the Material UI RadioGroup does not have an error prop. When the parent FormControl has an error state, the class Mui-error
is applied to the RadioGroup but there is no visual difference.

In my example, the FormLabel and FormHelperText change color as a visual indication that the FormControl has an error state. However, those are outside of the RadioGroup. The RadioGroup itself shows no change, but if desired we could use the auto-applied Mui-error
class to show some error styling.
MUI RadioGroup Disabled
The Material UI RadioGroup does not have a disabled
prop, just like it does not have error
. However, when the parent FormControl’s disabled
prop is true, the RadioGroup doesn’t even get a class of Mui-disabled
.
The children FormControlLabels do detect the parent FormControl’s disabled state and auto-apply a Mui-disabled
class.

This changes the visual presentation of the child FormControlLabels and Radios:

The DOM differences between error and disabled are surprising to me.
How to Style the MUI RadioGroup
Below is how the RadioGroup renders in the DOM. There’s no indication that it is a RadioGroup instead of a FormGroup, except for the role
and aria-labelledby
attributes.

The RadioGroup is also a simple one-element component. This makes styling easy. However, we may want to style child elements, and for that we need nested selectors. Here’s the styling for this tutorial:
<RadioGroup
sx={{
boxShadow: 3,
backgroundColor: "rgba(0,0,0,0.1)",
"& .MuiRadio-root": { color: "green" },
"& .MuiRadio-root.Mui-checked": { color: "orange" },
}}
/>
I applied a box shadow and background color on the RadioGroup. I then targeted the child Radio elements’ root class with a selector and set them to green. Finally, I set the selected radio to orange. MUI applies class Mui-checked
to make selectors easy on the checked element. Checkboxes receive this class as well.
Resources
Here are the MUI RadioGroup API docs.
Full code for this tutorial:
import { useCallback, useState } from "react";
import Radio from "@mui/material/Radio";
import RadioGroup from "@mui/material/RadioGroup";
import FormControlLabel from "@mui/material/FormControlLabel";
import FormControl from "@mui/material/FormControl";
import FormHelperText from "@mui/material/FormHelperText";
import FormLabel from "@mui/material/FormLabel";
const disabledText = "DISABLED";
const errorText = "ERROR";
const clearText = "NONE";
export default function RadioGroupExample() {
const [state, setState] = useState(clearText);
const handleRadioChange = (
event: React.ChangeEvent<HTMLInputElement>,
value: string
) => {
setState(value);
};
return (
<>
<form>
<FormControl
sx={{ m: 2 }}
variant="filled"
disabled={state === disabledText}
error={state === errorText}
>
<FormLabel id="radios">Set RadioGroup State</FormLabel>
<RadioGroup
aria-labelledby="radios"
name="quiz"
row
onChange={handleRadioChange}
defaultValue={clearText}
sx={{
boxShadow: 3,
backgroundColor: "rgba(0,0,0,0.1)",
"& .MuiRadio-root": { color: "green" },
"& .MuiRadio-root.Mui-checked": { color: "orange" },
}}
>
<FormControlLabel
value={errorText}
control={<Radio />}
label="Set ERROR"
/>
<FormControlLabel
value={disabledText}
control={<Radio />}
label="Set DISABLED"
/>
<FormControlLabel
value={clearText}
control={<Radio />}
label="Set NONE"
/>
</RadioGroup>
<FormHelperText>{state}</FormHelperText>
</FormControl>
</form>
</>
);
}