How To Create Custom Input Components With Formik, yup and Material-UI
Tags: javascript, react, beginners, webdev
Published: 2022-12-07 12:07:03

Components are building blocks for our UIs and with React, reusable, clean and efficient codes are easy. In this tutorial, we will learn how to create custom input field components with React, [material-ui](https://mui.com) and [yup] (https://www.npmjs.com/package/yup). We will use `material-ui` components in the `Formik Field` and implement validations using `yup`. 

**Introduction**

Forms are great features that are common in many web applications, creating a custom component with a popular `Javascript` library like `React` and `formik` is a straightforward process with decent functionalities and error handling.

**Create Project**

Lets create a new project using  `vite` command-line tool:

```javascript
 npm create vite@latest

```

This will prompt us to select the project Name( for this tutorial we used Formik-Input-component), Package name (formik-input-component), framework( React) and variant (JavaScript).
After all, we run the following code:

```javascript
  cd Formik-Input-component
  npm install
  npm run dev

```

Attached is the screenshot of the process:

![image showing the installation of react ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9r7p898ldzlc2p0vybtl.png)

**Installation**

Next, we will install `formik`, `yup`, and `material ui` packages using npm or yarn:

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

yarn install @mui/material @emotion/react @emotion/styled formik yup

```

**Implementation**

Once the packages are installed successfully, we can create a folder called `formikControl` where all our files will be saved. In the `formikControl` folder, we will create the following files

 * `FormikControl.jsx`
 * `Input.jsx`
 * `SelectInput.jsx`
 * `index.js`,
 * `TextError.jsx`

**Component**

 Let's start with with our `Input.jsx` file, we will do the following imports  into our file

---


```javascript

 import { Field, useField } from "formik";
 import PropTypes from "prop-types";
 import { FormLabel, Grid, TextField } from "@mui/material";

```
After the imports, we create a functional component and the following code:

```javascript

 const Input = (props) => {
 const { name, label, ...rest } = props;
 const [field] = useField(name);

  return (
    <Grid container direction="column">
      <FormLabel component="legend">{label}</FormLabel>
      <Field {...field} {...rest} as={TextField} />
    </Grid>
  );
};

Input.propTypes = {
  label: PropTypes.string,
  name: PropTypes.string,
};

export default Input

```
The `<Field/>` automatically hooks up our `TextField` to `Formik` courtesy of the `as` attribute.  We can render our `React` component and `formik` will automatically inject `onChange`, `onBlur`, `name`, and `value` props of the input field attributed to the name prop of the component. We destructed the `field` object from [usefield](https://formik.org/docs/api/useField) to perform this.

To be able to handle errors from the validations, we use our already created `<TextError/>` and render it beneath our <Field/>. To get the error messages, we destructure `ErrorMessage` from `formik` and pass in `<TextError/>` just like we did for TextField in <Field/>. Below is the new code that we have:

```javascript

import { ErrorMessage, Field, useField } from "formik";
import PropTypes from "prop-types";
import { FormLabel, Grid, TextField } from "@mui/material";
import TextError from "./TextError";
const Input = (props) => {
  const { name, label, ...rest } = props;
  const [field] = useField(name);

  return (
    <Grid container direction="column">
      <FormLabel component="legend">{label}</FormLabel>
      <Field {...field} {...rest} as={TextField} />
      <ErrorMessage name={name} as={TextError} />
    </Grid>
  );
};

Input.propTypes = {
  label: PropTypes.string,
  name: PropTypes.string.isRequired,
};

export default Input;

```

The next thing we do is to define our <TextError/>.

**TextError.jsx**

```javascript

import PropTypes from "prop-types";

const TextError = ({ children }) => {
  return <div style={{color:"red"}}>{children}</div>;
};

TextError.propTypes = {
  children: PropTypes.node,
};

export default TextError

```

The `<TextError/>` render any error that returns from the ErrorMessage and display it, 

> Note: we gave it a color red to show it's an error.

**Rendering Our Input Field**

To display our input fields to the user,  we try to make them seamless and easier to use. To do this, we import our Input component into our <FormikControl/>. Here is the complete code

```javascript

import Input from "./Input";
import PropTypes from "prop-types";
const FormikControl = ({ control, ...rest }) => {
  switch (control) {
    case "input":
      return <Input {...rest} />;
    // other cases...
     default:
    return null;
  }
};
FormikControl.propTypes = {
  control: PropTypes.string.isRequired,
};
export default FormikControl;

```

The `control` prop helps to switch between different types of input field created and the rest prop is used to pass other details passed to the input field component.

#### yaaah..... our component is ready for use......

To use the Component, we import it into a <Formik/> and render it just like it shown  below in `<App/>`

**App.jsx**

```javascript

import {  Grid,Button } from "@mui/material";
import {  Formik,Form } from "formik";
import FormikControl from "./FormikControl";
const App = () => {
  return (
    <Formik
      initialValues={{
        FullName: "",
      }}
      onSubmit={(values)=>console.log(values) }
    >
        <Form style={{ width: "100%" }}>
            <Grid container direction="column">
              <FormikControl
                control="input"
                label="Name"
                id="name"
                name="FullName"
                placeholder="Enter your name"
              />
           <Button type="submit">Submit</Button>
            </Grid>
          </Form>
        );
     
    </Formik>
  );
};
export default App;

```

Here, We imported our `<FormikControl/>` and rendered it inside  `Formik`, we passed our `initialValues`, and `onSubmit` Props. We must ensure that the `name` attribute in our `<FormikControl/>` matches the one in our `intialValues`. With that Formik automatically assigned values and other field props. 


**Yup implementation**

After creating our input components, we would like to add some validations to them, `yup` is a JavaScript schema builder for value parsing and validation. we already installed the package and use it we import it into our <App/>  and define the validation rules as shown below:

```javascript
import * as Yup from "yup" 
```

Next, we define our validation schema object as below

```javascript

 const validationSchema = Yup.object({
    FullName: Yup.string("Enter your Name").required("Name is required"),
  });

```

Here, we also use the name attribute that was used in <FormikControl/> i.e FullName as the key for the validation to work effectively.
Finally, we passed our `validationSchema` as a prop to the `Formik` component.  Here is the final code in `<App/>`.


**App.jsx**

```javascript

import { Form, Formik } from "formik";
import { Grid, Button } from "@mui/material";
import * as Yup from "yup";
import FormikControl from "./FormikControl";
const App = () => {
  const validationSchema = Yup.object({
    FullName: Yup.string("Enter your Name").required("name is required"),
  });

  return (
    <Formik
      initialValues={{
        FullName: "",
      }}
      validationSchema={validationSchema}
      onSubmit={(values) => console.log(values)}
    >
      <Form style={{ marginTop: "1rem", width: "100%" }}>
        <Grid container direction="column">
          <FormikControl
            control="input"
            label="Name"
            id="name"
            name="FullName"
            placeholder="Enter your FullName"
          />
        </Grid>
        <Button type="submit">Submit</Button>
      </Form>
    </Formik>
  );
};
export default App;

```

That ends our lesson on implementing a `<FormikControl />` with `yup`, `formik` and `material-ui`. The code is available in this [repo](https://github.com/isiakaabd/Formik-input-component) and I have also implemented input fields like textarea, radio, date, time, select and checkbox.

**Thanks for reading**