React form validation using material-ui and yup

May 15, 2020

React
Material-ui
form-validation
react-hook-form

Simple registration form with a full validation including checkbox field.

Working code example can be found on my github

Dependencies:

Starting from scrach

  1. Create a react project
$ npx create-react-app react-checkbox-material --template typescript
  1. Install dependencies
$ npm install -S yup --save
$ npm install -D @types/yup --save
$ npm install @material-ui/core --save
$ npm install react-hook-form --save
  1. If you are using typescript with react
$ npm install --save typescript @types/node @types/react @types/react-dom @types/jest

Coding

Validation schema

import * as yup from "yup";

const schema = yup.object().shape({
  email: yup.string().email("Incorrect format").required("E-mail is required"),
  password: yup
    .string()
    .required("Password is required")
    .min(4, "​Password must be at least 4 characters"),
  passwordConfirm: yup
    .string()
    .required("Passwords does not match")
    .oneOf([yup.ref("password"), null], "Passwords must match"),
  termsCheck: yup
    .boolean()
    .oneOf([true], "Required terms of use")
    .required("Required terms of use"),
});

export default schema;

Using useForm hook

Initialize useForm with created schema in order to use it later in the RegisterForm component.

import { useForm } from "react-hook-form";

interface FormData {
  email: string;
  password: string;
  passwordConfirm: string;
}

const Register = () => {
  const { register, handleSubmit, errors, setError } = useForm({
    validationSchema: registerSchema,
  });

  const submit = (data: FormData) => {
    console.log(data);
    // make an auth request and use setError to handle errors from there
  };

  return (
    <RegisterForm
      onSubmit={submit}
      register={register}
      formHandleSubmit={handleSubmit}
      errors={errors}
    />
  );
};

export default Register;

Register Material-ui TextFields

Each field needs to be register using inputRef in order to pass reference to the hook.

<TextField
  id="email"
  label="Email Address"
  name="email"
  autoComplete="email"
  inputRef={register}
  error={Boolean(errors.email)}
  helperText={errors.email ? errors.email.message : " "}
/>

Register Material-ui Checbox field

The situation with Checkbox is a little different since it is not getting parameters as TextField. To have it working we need to use component FormControlLabel:

import FormControlLabel from "@material-ui/core/FormControlLabel";

<FormControlLabel
  control={
    <Checkbox
      id="termsCheck"
      name="termsCheck"
      color="primary"
      required
    />
  }
  id="termsCheck"
  name="termsCheck"
  label={termsCheckboxLabel}
  inputRef={register}
/>
<FormHelperText error>
  {errors.termsCheck ? errors.termsCheck.message : " "}
</FormHelperText>

Submitting a form

<form
  className={classes.form}
  onSubmit={formHandleSubmit(onSubmit)}
  noValidate
>
// fields
</form>

Full form code

import Button from "@material-ui/core/Button";
import Checkbox from "@material-ui/core/Checkbox";
import Container from "@material-ui/core/Container";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import FormHelperText from "@material-ui/core/FormHelperText";
import Grid from "@material-ui/core/Grid";
import TextField from "@material-ui/core/TextField";
import Typography from "@material-ui/core/Typography";
import React from "react";
import { SignUpData } from "./interfaces";
import { useRegisterFormStyles } from "./styles";

export default function SignUp({
  onSubmit,
  formHandleSubmit,
  register,
  errors,
}: SignUpData) {
  const classes = useRegisterFormStyles();

  const termsCheckboxLabel = (
    <div>
      I accept <a href="/terms">terms of use</a>
    </div>
  );
  return (
    <Container component="main" maxWidth="xs">
      <div className={classes.paper}>
        <Typography component="h1" variant="h5">
          Register
        </Typography>
        <form
          className={classes.form}
          onSubmit={formHandleSubmit(onSubmit)}
          noValidate
        >
          <Grid container spacing={2}>
            <Grid item xs={12}>
              <TextField
                variant="outlined"
                required
                fullWidth
                id="email"
                label="Email Address"
                name="email"
                autoComplete="email"
                inputRef={register}
                error={Boolean(errors.email)}
                helperText={errors.email ? errors.email.message : " "}
              />
            </Grid>
            <Grid item xs={12}>
              <TextField
                variant="outlined"
                required
                fullWidth
                name="password"
                label="Password"
                type="password"
                id="password"
                inputRef={register}
                error={Boolean(errors.password)}
                helperText={errors.password ? errors.password.message : " "}
              />
            </Grid>
            <Grid item xs={12}>
              <TextField
                variant="outlined"
                required
                fullWidth
                name="passwordConfirm"
                label="Confirm Password"
                type="password"
                id="passwordConfirm"
                inputRef={register}
                error={Boolean(errors.passwordConfirm)}
                helperText={
                  errors.passwordConfirm ? errors.passwordConfirm.message : " "
                }
              />
            </Grid>
            <Grid item xs={12}>
              <FormControlLabel
                control={
                  <Checkbox
                    id="termsCheck"
                    name="termsCheck"
                    color="primary"
                    required
                  />
                }
                id="termsCheck"
                name="termsCheck"
                label={termsCheckboxLabel}
                inputRef={register}
              />
              <FormHelperText error>
                {errors.termsCheck ? errors.termsCheck.message : " "}
              </FormHelperText>
            </Grid>
          </Grid>
          <Button
            type="submit"
            fullWidth
            variant="contained"
            color="primary"
            className={classes.submit}
          >
            Register
          </Button>
        </form>
      </div>
    </Container>
  );
}

The end result

React form validation, react-hook-form, material-ui

Built with love to Python logo React logo Gatsby logo · Piotr Rogulski