2 ways to build forms using formik with Material UI + Yup!
Tags: react, webdev
Published: 2023-10-25 21:53:50

So, you've diving into the world of React, and, like me, you've found yourself using Formik to simplify form management while also making use of Material UI for attractive user interfaces. In this post, we'll explore two methods to combine these tools, resulting in functional and visually appealing forms.

First things first, make sure you have the libraries required installed:

```
npm install @mui/material @emotion/react @emotion/styled
```
```
 npm install formik
```
```
 npm install yup
```

Let's start with a basic example, laying the foundation for Formik's operation, including initial values, a validation schema, and an onSubmit function. We'll utilize Yup to create a straightforward validation schema.

```javascript
import * as yup from 'yup'

  const initialValues = {
    name: '',
    surname: '',
    phone: '',
    age: '',
  }

  const validationSchema = yup.object({
    name: yup.string().required().max(25).min(2),
    surname: yup.string().required().max(25).min(2),
    phone: yup.string().required(),
    age: yup.number()
  })
 
  const onSubmit = (data) => {
    console.log(data)
  }

```

Now, let's dive into the first way to integrate Formik with Material UI. We'll access the Formik component within a function to combine it with Material UI:

```javascript
import { Form, Formik } from "formik";

import { Button, Card, TextField } from "@mui/material";

...

<Card>
  <Formik
    initialValues={initialValues}
    validationSchema={validationSchema}
    onSubmit={onSubmit}
  >
    {(formik) => (
      <Form>
        <TextField
          label="Name"
          name="name"
          {...formik.getFieldProps("name")}
        />
    ...
        <Button
         variant="contained"
         type="submit"
         color="success"
        >
         Submit
        </Button>
      </Form>    
    )}
  </Formik>
</Card>
...


```

Using {...formik.getFieldProps("name")} simplifies form state management, automatically handling values, onBlur, and onChange events, along with error handling, for the 'name' field.

Next, let's ensure our validation messages appear in Material UI, but only after the user has interacted with the field. 

![Input field for user name](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qbxz67ivufi3x0elhie0.PNG)

To achieve this, we can use Formik in conjunction with the Material UI TextField's error and helperText properties:

```javascript

...

<TextField
  label="Name"
  name="name"
  {...formik.getFieldProps("name")}    
  error={formik.touched.name && !!formik.errors.name}
  helperText={formik.touched.name && formik.errors.name}
/>
...

```

Now, if you require more control over the TextField component, there's another approach to integrate it. You can wrap the TextField with the `<Field>` component from Formik. This grants you extra resources, such as custom validation functions and access to meta data:

```javascript
...

// While Formik can handle this validation as well, let's explore a custom approach for the sake of this example :)

const customValidation = (value) => {
  const regex = /^[A-Za-z\s]+$/; // Regular expression to match alphabets and spaces

  if (!value || !regex.test(value)) {
    return 'Name should contain only letters and spaces';
  }
  return undefined; // Validation passed
};

...

<Field name="name" validate={customValidation}>
  {({ field, meta }) => (
    <TextField
      {...field}
      label="Name"
      error={meta.touched && !!meta.error}
      helperText={meta.touched && meta.error}
    />
  )}
</Field>

```

That's it for this post. I hope it has helped clarify how to move forward if you are trying to implement these tools together! 😄