Reusable Form Components using React + Formik + Yup

Author

AWS certified Developer Associate + React.js

Reusable Form Components using React + Formik + Yup

July 23, 2021

formikreact

Reusable Form Components using React + Formik + Yup

Introduction

This Blog helps to build a simple form with basic elements like input, textarea, radio, select, and checkbox using formik that manage form data, submission, and validation .

What is Formik and Why Formik Form?

Formik is a small group of React components and hooks for building forms in React and React Native.

Formik Forms not only helps in managing form data, form submission, form validation, and displaying error messages but also helps you to deal with forms in a scalable, performant, easy way and one more important thing is, it supports advanced validation with Yup.

What is Yup?

Yup is a JavaScript schema builder for value parsing and validation. Define a schema, transform a value to match, validate the shape of an existing value, or both. Yup schema is extremely expressive and allows modelling complex, interdependent validations, or value transformations.

Prerequisites

  • HTML
  • CSS
  • Javascript + ES6
  • React

Installation

npm install --save formik yup

Lets Build

We shall have 3 Components :

  1. FormikWrapper
  2. FormikController
  3. FormElement

FormikWrapper.js

We use this component as a simple reusable formik wrapper.

import React from "react"
import { Formik, Form } from "formik"
import * as Yup from "yup"
import FormikController from "FormikController.js"

function FormikWrapper() {
  const choices = [
    { key: "choice a", value: "choicea" },
    { key: "choice b", value: "choiceb" },
  ]

  const initialValues = {
    email: "",
    description: "",
    selectChoice: "",
    radioChoice: "",
    checkBoxChoice: "",
  }
  const validationSchema = Yup.object({
    email: Yup.string().required("Required"),
    description: Yup.string().required("Required"),
    selectChoice: Yup.string().required("Required"),
    radioChoice: Yup.string().required("Required"),
    checkBoxChoice: Yup.array().required("Required"),
  })
  const onSubmit = values => console.log("Form data", values)
  return (
    <Formik
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={onSubmit}
    >
      {formik => (
        <Form>
          <FormikController
            control="input"
            type="email"
            label="Email"
            name="email"
          />
          <FormikController
            control="textarea"
            label="Description"
            name="description"
          />
          <FormikController
            control="select"
            label="Select your choice"
            name="selectChoice"
            option={choices}
          />
          <FormikController
            control="radio"
            label="Click your choice"
            name="radioChoice"
            option={choices}
          />
          <FormikController
            control="checkbox"
            label="select your choices"
            name="checkBoxChoice"
            option={choices}
          />
          <button type="submit">Submit</button>
        </Form>
      )}
    </Formik>
  )
}
export default FormikContainer

FormikController.js

This component is capable of rendering different types of form elements based on particular prop.

import React from "react"
import Input from "Input.js"
import TextArea from "TextArea.js"
import Select from "Select.js"
import RadioButtons from "RadioButton.js"
import CheckBoxes from "CheckBoxes.js"

function FormikController(props) {
  const { control, ...rest } = props
  switch (control) {
    case "input":
      return <Input {...rest} />
    case "textArea":
      return <TextArea {...rest} />
    case "select":
      return <Select {...rest} />
    case "radio":
      return <RadioButtons {...rest} />
    case "checkbox":
      return <CheckBoxes {...rest} />
    default:
      return null
  }
}
export default FormikController

FormElement.js

This component is the core form element which includes,

  1. Input
  2. TextArea
  3. Select
  4. RadioButtons
  5. Checkboxes

Component for Input Element

In this Input Formik control component, there are 3 distinct elements <label/> an HTML element, <Field/> a Formik Component, <ErrorMessage/> an error message component from formik.

import React from "react"
import { Field, ErrorMessage } from "formik"

function Input(props) {
  const { name, label, ...rest } = props
  return (
    <div>
      <label htmlFor={name}> {label}</label>
      <Field name={name} {...rest} />
      <ErrorMessage name={name} />
    </div>
  )
}
export default Input

Component for TextArea Element

Here also there are 3 main elements , <label/> an HTML element,<ErrorMessage/> an error message component from formik and <Field/> a Formik Component which inturn render textarea HTML element.

import React from "react"
import { Field, ErrorMessage } from "formik"

function Textarea(props) {
  const { label, name, ...rest } = props
  return (
    <div>
      <label htmlFor={name}>{label}</label>
      <Field as="textarea" id={name} name={name} {...rest} />
      <ErrorMessage name={name} />
    </div>
  )
}
export default TextArea

Component for Select Element

Here <Field/> a Formik Component which inturn renders select HTML element, Onclick of the field renders a dropdown with list of option to choose from, this has to be considered when creating our Select component and rest are same as above.

import React from "react"
import { Field, ErrorMessage } from "formik"

function Select(props) {
  const { label, name, options, ...rest } = props
  return (
    <div>
      <label htmlFor={name}>{label}</label>
      <Field as="select" id={name} name={name} {...rest}>
        {options.map(option => {
          return (
            <option key={option.value} value={option.value}>
              {option.key}
            </option>
          )
        })}
      </Field>
      <ErrorMessage name={name} />
    </div>
  )
}

export default Select

Component for RadioButtons Element

<Field/> is a list of input and label elements that allows you to make one selection, this has to be considered when creating a radio button component.

import React from "react"
import { Field, ErrorMessage } from "formik"

function RadioButtons(props) {
  const { label, name, options, ...rest } = props
  return (
    <div>
      <label>{label}</label>
      <Field name={name}>
        {formik => {
          const { field } = formik
          return options.map(option => {
            return (
              <div key={option.key}>
                <input
                  type="radio"
                  id={option.value}
                  {...field}
                  {...rest}
                  value={option.value}
                  checked={field.value === option.value}
                />
                <label htmlFor={option.value}>{option.key}</label>
              </div>
            )
          })
        }}
      </Field>
      <ErrorMessage name={name} />
    </div>
  )
}

export default RadioButtons

Component for CheckBoxes Element

Here also <Field/> is a list of input and label elements that allows you to make one or more selections.

import React from "react"
import { Field, ErrorMessage } from "formik"

function Checkboxes(props) {
  const { label, name, options, ...rest } = props
  return (
    <div>
      <label>{label}</label>
      <Field name={name}>
        {formik => {
          const { field } = formik
          return options.map(option => {
            return (
              <div key={option.key}>
                <input
                  type="checkbox"
                  id={option.value}
                  {...field}
                  {...rest}
                  value={option.value}
                  checked={field.value.includes(option.value)}
                />
                <label>{option.key}</label>
              </div>
            )
          })
        }}
      </Field>
      <ErrorMessage name={name} />
    </div>
  )
}

export default Checkboxes

Conclusion

We can extend it to a custom React Hook that returns Formik states and helpers. It is used internally to create the component and is also a high performant.

References

Antstack Blog Post
Antstack Blog Post

Are you planning to go to serverless? AntStack is a cloud computing service and consulting company primarily focusing on Serverless Computing. We help companies get up and running with serverless, and we’ll make sure that there are no limits.

Keep track of our socials and connect with us - LinkedIn

event bannerevent bannerevent banner