The Essential Guide to Submitting MUI Forms (2 Methods)

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:

MUI Form with Submit Button
MUI Form with Submit Button

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:

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.

MUI Form with HTML Submit
MUI Form with HTML Submit

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.

Resources

MUI Checkbox Docs

MUI Rating Docs

MUI TextField Docs

Share this post:

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.