MUI forms can be submitted using good old-fashioned HTML or submitted using React hooks for state tracking. In this tutorial I will look at the network traffic and code differences to compare and contrast.
MUI uses the React Form component as a wrapper around MUI input subcomponents. In other words, MUI does not have it’s own form component. It does have every conceivable input component as well as a custom button that can handle form submission.
Below is the form we will create:

Here are the questions I intend to answer:
- Does “HTML form submit” work as expected in MUI?
- Will HTML form submission pick up the Review component value?
- What are the pros and cons of hooks for forms?
Here are additional useful reads about Forms:
- Every Material-UI Form Component Explained
- The Definitive Guide to Material-UI Form Layout
- Understanding MUI Labels: TextField Labels, Input Labels, and Form Labels
- The Ultimate Guide to Material-UI FormControl: 3 Examples
- The Ultimate MUI Switch Example: Color, onChange, More
MUI Form Submit with a Submit Button
Creating a form in MUI and relying on HTML submission attributes is a clean method for pushing data to an endpoint. It requires very little JavaScript code and there is no need for state management.
The following is required:
- A
name
attribute on each input element type="submit"
attribute on the Button- An
action
attribute on the form element (submit works without this, but submits to the current page) - A
value
attribute on the checkboxes (submit works without this, but default value is ‘on’)
Here’s the code for my example:
import * as React from "react";
import {
Button,
Checkbox,
FormControlLabel,
FormGroup,
FormLabel,
Rating,
TextField,
Typography
} from "@mui/material";
export default function FormSubmitHTML() {
return (
<form action="/somewhere.html">
<FormGroup sx={{padding: 2, borderRadius: 2, border: '1px solid', borderColor: 'primary.main'}}>
<TextField sx={{paddingBottom: 2}} name="specs" variant="outlined" placeholder="Specs..." />
<FormLabel component="legend">Product</FormLabel>
<FormGroup row sx={{paddingBottom: 2}}>
<FormControlLabel control={<Checkbox name="laptop" value="yes" />} label="Laptop" />
<FormControlLabel
control={<Checkbox name="headset" value="yes" />}
label="Head Set"
/>
</FormGroup>
<Typography component="legend">Review</Typography>
<Rating
name="review"
sx={{paddingBottom: 2}}
/>
<Button type="submit" variant="outlined">Submit</Button>
</FormGroup>
</form>
);
}
The submission adds a query parameter to the URL for each input. If the TextField or Rating input are unpopulated, they are still added to the URL but has no value (but not the checkbox).
In this tutorial I set the values to “1 TB SSD”, laptop=checked, and a 4 star rating.

Here’s the URL generated by the form code above:
http://localhost:3000/somewhere.html?specs=1TB+SSD&laptop=yes&review=4
Notice that this method uses a ‘typical’ MUI Button component. You can take advantage of all features available for styling the button.
MUI Form Submit with React Hooks
Using hooks to control the form takes far more code but also gives more control (and more challenges).
The goal is to set a state object that “knows” the value of each form subcomponent. Each subcomponent needed a unique change handler because they all passed data a little differently.
The TextField used a straightforward handler where I extracted the name and value from the event and pushed them to the state object.
The Checkboxes used similar code, but they also passed a checked
value. This is required for uncheck to set the state properly because the checkbox value
attribute is constant (it’s always ‘yes’ in my example). It’s the checked
attribute that changes based on check state.
The Rating passes in a value
prop to it’s handler so we don’t have to extract it from the target
.
import React, { useState } from "react";
import {
Button,
Checkbox,
FormControlLabel,
FormGroup,
FormLabel,
Rating,
TextField,
Typography,
} from "@mui/material";
interface FormValues {
specs?: string;
laptop?: string;
headset?: string;
review?: number;
}
const reviewName = 'review';
export default function FormSubmitHooks() {
const [formValues, setFormValues] = useState<FormValues>({});
const handleTextFieldChange = (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
) => {
const { name, value } = event.target;
setFormValues({
...formValues,
[name]: value,
});
};
const handleCheckboxChange = (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
checked?: boolean
) => {
const { name } = event.target;
if(!checked) {
//@ts-ignore still working on the typing
delete formValues[name]
} else {
setFormValues({
...formValues,
[name]: checked,
});
}
};
const handleRatingChange = (
value: number | null,
name: string
) => {
setFormValues({
...formValues,
[name]: value,
});
};
const handleSubmit = () => {
fetch('/somewhere.html', {
method: 'POST',
body: JSON.stringify(formValues),
headers: {
'Content-Type': 'application/json'
},
})
}
return (
<form>
<FormGroup
sx={{
padding: 2,
borderRadius: 2,
border: "1px solid",
borderColor: "primary.main",
}}
>
<TextField
sx={{ paddingBottom: 2 }}
name="specs"
variant="outlined"
placeholder="Specs..."
onChange={handleTextFieldChange}
/>
<FormLabel component="legend">Product</FormLabel>
<FormGroup row sx={{ paddingBottom: 2 }} >
<FormControlLabel
control={<Checkbox name="laptop" value="laptop" onChange={handleCheckboxChange}/>}
label="Laptop"
/>
<FormControlLabel
control={<Checkbox name="headset" value="headset" onChange={handleCheckboxChange}/>}
label="Head Set"
/>
</FormGroup>
<Typography component="legend">Review</Typography>
<Rating name={reviewName} sx={{ paddingBottom: 2 }} onChange={(event, value) => handleRatingChange(value, reviewName)}/>
<Button variant="outlined" onClick={handleSubmit}>Submit</Button>
</FormGroup>
</form>
);
}
Using hooks, I had to add lots of code to control what fields appeared or were removed from the state object before submission. I also have to use a library like fetch to handle the post to an endpoint.
The benefit of hooks is I can modify the data programmatically or use it in other components.