rogulski.it

My name is Piotr, a passionate pythonista and this is my blog!

    React form validation using material-ui and yup

    Posted at — May 16, 2020

    Simple registration form with a full validation including checkbox field.

    Working code example can be found on my github

    Dependencies:

    Starting from scratch

    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