🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
REFERENCEreact

react Documentation

LOADING ENGINE...

Formik

AI & DATA SCIENCE // formik

Formik is a popular React library that handles form state, validation, and submission logic, reducing the boilerplate needed for complex forms compared to writing everything by hand.

Syntax

npm install formik

<Formik initialValues={...} onSubmit={...} validate={...}>
  {/* form fields */}
</Formik>

Deep Dive Course

Formik manages a form's values, validation errors, and touched-field tracking internally, exposing them through its render props or hooks like useFormik, so individual form fields, typically Formik's own Field component, or plain inputs wired to Formik's provided handlers, don't each need their own separate useState and onChange wiring. It supports validation either through a custom validate function returning an errors object, or by integrating a schema-validation library like Yup via the validationSchema prop, and handles calling your onSubmit function only once validation has actually passed.

1Understanding Formik

Formik manages a form's values, validation errors, and touched-field tracking internally, exposing them through its render props or hooks like useFormik, so individual form fields, typically Formik's own Field component, or plain inputs wired to Formik's provided handlers, don't each need their own separate useState and onChange wiring. It supports validation either through a custom validate function returning an errors object, or by integrating a schema-validation library like Yup via the validationSchema prop, and handles calling your onSubmit function only once validation has actually passed.

💡

Pair Formik with Yup's validationSchema prop instead of writing a custom validate function by hand for anything beyond the simplest validation rules — Yup's declarative schema syntax scales much more cleanly to forms with many interdependent validation rules.

editor.html
import { Formik, Form, Field } from 'formik';

function SignupForm() {
  return (
    <Formik
      initialValues={{ email: '' }}
      onSubmit={(values) => console.log('Submitted:', values)}
    >
      <Form>
        <Field name="email" type="email" />
        <button type="submit">Sign Up</button>
      </Form>
    </Formik>
  );
}
localhost:3000

2Practical Example

Here is a real-world application of Formik showing how it is used in production React code.

editor.html
import * as Yup from 'yup';

const schema = Yup.object({
  email: Yup.string().email('Invalid email').required('Required')
});

// <Formik validationSchema={schema} ...>
localhost:3000

3Best Practices

Follow these guidelines when working with Formik:

1. Use Formik's Field component, or its handleChange/handleBlur/values from useFormik, instead of manually wiring up individual useState calls and onChange handlers per field

2. Use a Yup validationSchema for anything beyond trivial validation, rather than writing an increasingly complex custom validate function by hand

3. Rely on Formik's built-in touched and errors tracking to control exactly when a field's error message should actually be shown, rather than reimplementing that timing logic yourself

⚠️

Tip: Pair Formik with Yup's validationSchema prop instead of writing a custom validate function by hand for anything beyond the simplest validation rules — Yup's declarative schema syntax scales much more cleanly to forms with many interdependent validation rules.

editor.html
import { Formik, Form, Field } from 'formik';

function SignupForm() {
  return (
    <Formik
      initialValues={{ email: '' }}
      onSubmit={(values) => console.log('Submitted:', values)}
    >
      <Form>
        <Field name="email" type="email" />
        <button type="submit">Sign Up</button>
      </Form>
    </Formik>
  );
}
localhost:3000

Examples

Example 01Basic Usage
import { Formik, Form, Field } from 'formik';

function SignupForm() {
  return (
    <Formik
      initialValues={{ email: '' }}
      onSubmit={(values) => console.log('Submitted:', values)}
    >
      <Form>
        <Field name="email" type="email" />
        <button type="submit">Sign Up</button>
      </Form>
    </Formik>
  );
}
Example 02Advanced Example
import * as Yup from 'yup';

const schema = Yup.object({
  email: Yup.string().email('Invalid email').required('Required')
});

// <Formik validationSchema={schema} ...>

Best Practices

  • Use Formik's Field component, or its handleChange/handleBlur/values from useFormik, instead of manually wiring up individual useState calls and onChange handlers per field
  • Use a Yup validationSchema for anything beyond trivial validation, rather than writing an increasingly complex custom validate function by hand
  • Rely on Formik's built-in touched and errors tracking to control exactly when a field's error message should actually be shown, rather than reimplementing that timing logic yourself

Interview Question

Why does using a library like Formik typically reduce the amount of code needed for a form with many fields, compared to manually writing a useState call and onChange handler for each individual field?

Hint: Think about how many times the same basic value-tracking and change-handling pattern repeats across a large hand-rolled form, and what Formik centralizes instead.

A hand-rolled form with several fields typically repeats the exact same basic pattern for every single field: some way to store its current value, a handler reading the new value from an onChange event and updating that stored value, and separate logic to track whether that specific field has been touched and display its corresponding error message at the right time — none of these individual pieces are complicated, but the sheer repetition across many fields adds up to a meaningful amount of largely identical boilerplate. Formik centralizes all of that shared logic, tracking every field's value, touched status, and validation errors together in one internal state object, and exposes generic, reusable handlers and components, like Field and handleChange, that automatically work correctly for any field based on its name attribute, without needing field-specific code written out individually for each one. This means adding another field to a Formik-managed form typically just means adding another Field element, rather than writing an entirely new set of state and handler logic for it.

Exercises

MediumPractice using Formik in a real scenario.
View Solution
import { Formik, Form, Field } from 'formik';

function SignupForm() {
  return (
    <Formik
      initialValues={{ email: '' }}
      onSubmit={(values) => console.log('Submitted:', values)}
    >
      <Form>
        <Field name="email" type="email" />
        <button type="submit">Sign Up</button>
      </Form>
    </Formik>
  );
}

Frequently Asked Questions

Why does using a library like Formik typically reduce the amount of code needed for a form with many fields, compared to manually writing a useState call and onChange handler for each individual field?

A hand-rolled form with several fields typically repeats the exact same basic pattern for every single field: some way to store its current value, a handler reading the new value from an onChange event and updating that stored value, and separate logic to track whether that specific field has been touched and display its corresponding error message at the right time — none of these individual pieces are complicated, but the sheer repetition across many fields adds up to a meaningful amount of largely identical boilerplate. Formik centralizes all of that shared logic, tracking every field's value, touched status, and validation errors together in one internal state object, and exposes generic, reusable handlers and components, like Field and handleChange, that automatically work correctly for any field based on its name attribute, without needing field-specific code written out individually for each one. This means adding another field to a Formik-managed form typically just means adding another Field element, rather than writing an entirely new set of state and handler logic for it.

Related Functions

react-hook-formform-validationform-handling