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.
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>
);
}2Practical Example
Here is a real-world application of Formik showing how it is used in production React code.
import * as Yup from 'yup';
const schema = Yup.object({
email: Yup.string().email('Invalid email').required('Required')
});
// <Formik validationSchema={schema} ...>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.
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>
);
}