The MUI FormControl component is used as a high-level wrapper around subcomponents in a form. Its primary purpose is state management.
We will create a form that has three FormControl components inside, each wrapping a row of components.

In many UIs that use forms, likely only one FormControl would be used and would wrap all the child components to manage their state together.
The FormControl has several props for controlling state. The remaining props are used for sizing and spacing.
Here’s a YouTube version of this post or watch below:
MUI FormControl Layout
The FormControl can be used to manage layout, especially if display: "flex"
is passed to the sx
prop. I will show how to do this here just for demo purposes. However, the FormGroup component is actually built for layout and I recommend using it instead.
The code below creates the first MUI Select and MUI TextField seen in the intro screenshot. I ran into several interesting problems as I worked on this section.
<FormControl
margin="normal"
color="primary"
variant="filled"
sx={{display: 'flex', flexDirection: 'row', justifyContent: 'space-around'}}
>
{/* <FormGroup row sx={{justifyContent: 'space-around' }}> */}
<Box>
<InputLabel sx={{left: 'auto'}} id="custom-select-label">Score</InputLabel>
<Select
sx={{ width: 300 }}
label={"Score"}
MenuProps={{
PaperProps: { sx: { maxHeight: 200 } }
}}
>
{scoreData.map((scoreValue) => {
return <MenuItem value={scoreValue}>{scoreValue}</MenuItem>
})}
</Select>
</Box>
<TextField
sx={{ width: 300 }}
label="Name"
variant="filled"
placeholder="Name"
/>
{/* </FormGroup> */}
</FormControl>
The first issue is that justifyContent: "space-around"
doesn’t play well with InputLabel inside FormControl. The FormControl cleverly adds left: 0
to the InputLabel so that it will slip inside the first component (the Select in this tutorial).
However, space-around
pushes the Select to the right.

To solve this, I wrapped a Box component around the Select and InputLabel. This meant the Box was pushed to the right instead. Next, I added left: "auto"
to the InputLabel so that it would not be at left: 0
still.
The next issue I faced was controlling layout without using a FormGroup. I added a commented out FormGroup to show how much less code is required to control flex with a FormGroup compared to a FormControl.
//Required for FormControl but not FormGroup
sx={{ display: 'flex', flexDirection: 'row', justifyContent: 'space-around' }}
However, the FormGroup does add an extra div to the DOM.

MUI FormControl Error
FormControl is at its best when it is managing state for children components. Here’s an example where the FormControl error
prop is given a value of true
.
<FormControl variant="filled" margin="normal" error sx={{ width: '100%', marginTop: 2 }}>
<FormGroup row sx={{ justifyContent: 'space-around' }}>
<Select
sx={{ width: 300 }}
label={"Score"}
MenuProps={{
PaperProps: { sx: { maxHeight: 200 } }
}}
>
{scoreData.map((scoreValue) => {
return <MenuItem value={scoreValue}>{scoreValue}</MenuItem>
})}
</Select>
<FormGroup row={false} sx={{ minWidth: 300 }}>
<FormLabel component="legend">Form Switch</FormLabel>
<FormControlLabel
control={
<Switch
name="switch1"
/>
}
label="Switch 1"
/>
<FormControlLabel
control={
<Switch
name="switch2"
/>
}
label="Switch 2"
/>
<FormControlLabel
control={
<Switch
name="switch3"
/>
}
label="Switch 3"
/>
<FormHelperText>Switch Group</FormHelperText>
</FormGroup>
</FormGroup>
</FormControl>
The error state affects the color style of the subcomponents but it does not affect their functionality. The Select and Switches are still usable.

MUI FormControl Disabled
In the code below I use the disabled
prop to disable the children components of a FormControl. However, an interesting problem occurred when one of the child components was a TextField.
<FormControl variant="filled" margin="normal" disabled={disabled} fullWidth>
<FormGroup row sx={{ justifyContent: 'space-around' }}>
<Select
sx={{ width: 300 }}
label={"Score"}
MenuProps={{
PaperProps: { sx: { maxHeight: 200 } }
}}
>
{scoreData.map((scoreValue) => {
return <MenuItem value={scoreValue}>{scoreValue}</MenuItem>
})}
</Select>
<TextField
sx={{ width: 300 }}
label="Name"
variant="filled"
placeholder="Name"
disabled={disabled}
/>
</FormGroup>
</FormControl>
The TextField is composed of several components, including an Input and a FormControl. The TextField did not inherit the disabled state from the initial FormControl, but instead had to use its own disabled
prop to enter a disabled state.
To control both FormControls at the same time, I created a const named disabled
. React useState would be a good way to control this value.

Resources
Check out the additional posts on Form components:
“Its” is spelled wrongly in the second sentence. It’s “of it”, not “it is” or “it has”.
Good catch! Fixed.