Written by: ekwoster.dev on Tue Sep 02

πŸ”₯ Stop Writing Boilerplate in React: Unlock the Hidden Power of Formik with Yup & Custom Hooks!

πŸ”₯ Stop Writing Boilerplate in React: Unlock the Hidden Power of Formik with Yup & Custom Hooks!

Cover image for πŸ”₯ Stop Writing Boilerplate in React: Unlock the Hidden Power of Formik with Yup & Custom Hooks!

πŸ”₯ Stop Writing Boilerplate in React: Unlock the Hidden Power of Formik with Yup & Custom Hooks!

Tired of copying and pasting the same form validation logic again and again in your React projects? You're not alone. Forms are essential in web apps β€” login forms, registration forms, checkout forms, contact forms β€” the list goes on. But building and validating forms in React can quickly become a nightmare of state handlers, validations, and spaghetti code.

So let me show you a way out.

In this post, we're going to deep-dive into how Formik, combined with the Yup validation library and some custom hooks, can help you completely eliminate form boilerplate and elevate your developer experience (we're talking about never thinking about onChange again).

And this is not just another Formik tutorial. We’ll introduce an unconventional pattern using dynamic field rendering and reusable form components with context-driven data.

Ready? Let’s code like it’s 2030.


πŸš€ TL;DR

We’ll build a dynamic form component that:

  • Uses Formik for form state management
  • Uses Yup for reusable schema validation
  • Dynamically renders fields based on a schema
  • Supports custom field types
  • Is DRY, reusable, and sexy.

Formik-yup-custom-form


🧠 Why Even Bother with Formik + Yup?

Let’s be real β€” native form handling in React is a hassle. For a simple form with even basic validation, you might end up managing multiple state variables, a bunch of error conditions, and field-level logic that repeats across files.

Formik was built to reduce that pain. It abstracts away the form state and helps with validations, touched fields, error messages, and more.

Yup, on the other hand, is a schema validation library β€” think Joi, but more friendly and declarative for frontend forms.

When you merge these two tools with clever abstractions, magic happens.✨


πŸ§ͺ Let's Build a Fully Dynamic Form

Imagine you have a form schema like this:

const formSchema = [
  { name: 'email', type: 'text', label: 'Email', required: true },
  { name: 'password', type: 'password', label: 'Password', required: true },
  { name: 'acceptTerms', type: 'checkbox', label: 'Accept Terms', required: true }
];

This could come from a CMS, a config file, or your API. Now how about rendering an entire validated form based on this schema β€” in a completely reusable and abstracted way?

Let’s break this into 3 parts:

1. βœ… Dynamic Yup Schema Generator

import * as Yup from 'yup';

const generateValidationSchema = (schema) => {
  const shape = {};

  schema.forEach(field => {
    let validator;

    switch (field.type) {
      case 'text':
      case 'password':
        validator = Yup.string();
        if (field.required) {
          validator = validator.required(`${field.label} is required`);
        }
        break;
      case 'checkbox':
        validator = Yup.bool();
        if (field.required) {
          validator = validator.oneOf([true], `You must accept the terms`);
        }
        break;
      default:
        validator = Yup.mixed();
    }

    shape[field.name] = validator;
  });

  return Yup.object().shape(shape);
};

Boom. This allows you to dynamically generate a Yup schema based on a simple config.

2. 🌈 Reusable Field Renderer Component

const DynamicField = ({ field, formik }) => {
  const { name, type, label } = field;

  switch (type) {
    case 'text':
    case 'password':
      return (
        <div>
          <label>{label}</label>
          <input
            name={name}
            type={type}
            value={formik.values[name]}
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
          />
          {formik.touched[name] && formik.errors[name] && (
            <div className="error">{formik.errors[name]}</div>
          )}
        </div>
      );
    case 'checkbox':
      return (
        <div>
          <label>
            <input
              name={name}
              type="checkbox"
              checked={formik.values[name]}
              onChange={formik.handleChange}
              onBlur={formik.handleBlur}
            />
            {label}
          </label>
          {formik.touched[name] && formik.errors[name] && (
            <div className="error">{formik.errors[name]}</div>
          )}
        </div>
      );
    default:
      return null;
  }
};

Add styles and accessibility later β€” this is just the logic.

3. 🧩 Master Form Component With Schema Logic

import { Formik, Form } from 'formik';

const DynamicForm = ({ schema }) => {
  const initialValues = schema.reduce((acc, field) => {
    acc[field.name] = field.type === 'checkbox' ? false : '';
    return acc;
  }, {});

  const validationSchema = generateValidationSchema(schema);

  const handleSubmit = (values) => {
    console.log('Form submitted:', values);
  };

  return (
    <Formik
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={handleSubmit}
    >
      {(formik) => (
        <Form>
          {schema.map(field => (
            <DynamicField
              key={field.name}
              field={field}
              formik={formik}
            />
          ))}
          <button type="submit">Submit</button>
        </Form>
      )}
    </Formik>
  );
};

Yes, that's it. You now have a generic component that works for arbitrary form configurations, with Yup validation fully integrated.


🧠 Bonus: Add Custom Field Types (Dropdown, Date, etc)

To add more field types, just extend the DynamicField component. Want a date picker? Autocomplete? Multiselect? Sky's the limit.


πŸ§ͺ Real-World Application: Think Beyond Static Forms

You can use this pattern for:

  • Custom form builders (like Typeform, Google Forms)
  • Admin panels with user-defined forms
  • Product configuration flows
  • CMS-driven apps that define fields in JSON
  • Onboarding flows

Once you empower your forms through configuration + Yup + Formik, everything becomes easier.


🧼 Wrapping Up

Formik on its own is powerful. But once you pair it with Yup and push abstraction, you can remove 90% of form-related boilerplate from your React project.

And if you’re just starting β€” even better. You’re learning a modern solution that can grow with your projects and future-proof your code.

Go ahead, try implementing a fully dynamic form UI in your next app. Convert hardcoded forms to this system β€” you won’t look back.

Let the code work for you. 🎯


πŸ“š Further Reading

Happy coding! πŸ’»

πŸ’‘ If you need help building modern frontends with highly reusable components, we offer Frontend Development services.