Build forms in React, without the tears
Formik is a battle-tested library for managing form state in React and React Native applications. It abstracts the repetitive parts of form handling—tracking field values, validation errors, touched states, and submission flows—into a cohesive API built on React hooks and components. With over 3.4 million weekly downloads, it's trusted by production applications that need robust form logic without coupling to external state managers like Redux.
The library emerged to solve three universal form problems: getting values in and out of form state, validation and error messages, and handling submission. Formik provides the useFormik hook for programmatic control and declarative components like <Formik>, <Field>, and <ErrorMessage> for markup-driven forms. It integrates seamlessly with Yup for schema validation and supports dynamic field arrays through <FieldArray>, making it suitable for everything from login forms to multi-step surveys.
Formik targets teams building complex forms where re-render performance is acceptable and component-based structure is preferred. It shines in React Native projects where alternatives like React Hook Form have limited support. Companies choose it for maintainability: the declarative API reduces boilerplate compared to manual useState implementations, and field-level validation helpers (handleBlur, touched) provide granular UX control out of the box.
The library ships with TypeScript definitions and maintains a small footprint for a feature-complete solution. Version 2.4.9 represents a stable API that hasn't required breaking changes in years, though this also means it predates some newer hooks-first patterns. Developers appreciate its explicit handling of submission states (isSubmitting, isValidating) and programmatic form manipulation (setFieldValue, resetForm), which are verbose but predictable in large codebases.
import React from 'react';
import { useFormik } from 'formik';
import * as Yup from 'yup';
const SignupForm = () => {
const formik = useFormik({
initialValues: {
email: '',
password: '',
confirmPassword: ''
},
validationSchema: Yup.object({
email: Yup.string()
.email('Invalid email address')
.required('Required'),
password: Yup.string()
.min(8, 'Must be at least 8 characters')
.required('Required'),
confirmPassword: Yup.string()
.oneOf([Yup.ref('password')], 'Passwords must match')
.required('Required')
}),
onSubmit: async (values, { setSubmitting, resetForm }) => {
await fetch('/api/signup', {
method: 'POST',
body: JSON.stringify(values),
headers: { 'Content-Type': 'application/json' }
});
resetForm();
setSubmitting(false);
}
});
return (
<form onSubmit={formik.handleSubmit}>
<div>
<input
type="email"
{...formik.getFieldProps('email')}
placeholder="Email"
/>
{formik.touched.email && formik.errors.email && (
<div style={{ color: 'red' }}>{formik.errors.email}</div>
)}
</div>
<div>
<input
type="password"
{...formik.getFieldProps('password')}
placeholder="Password"
/>
{formik.touched.password && formik.errors.password && (
<div style={{ color: 'red' }}>{formik.errors.password}</div>
)}
</div>
<div>
<input
type="password"
{...formik.getFieldProps('confirmPassword')}
placeholder="Confirm Password"
/>
{formik.touched.confirmPassword && formik.errors.confirmPassword && (
<div style={{ color: 'red' }}>{formik.errors.confirmPassword}</div>
)}
</div>
<button type="submit" disabled={formik.isSubmitting}>
{formik.isSubmitting ? 'Submitting...' : 'Sign Up'}
</button>
</form>
);
};
export default SignupForm;Multi-step wizards and surveys where form state persists across navigation: Formik's centralized values object and setValues make it straightforward to save progress, validate sections independently, and merge data on final submission without prop drilling.
Dynamic form builders like admin panels or CRM tools: The <FieldArray> component provides push, remove, and insert helpers for managing repeating field groups (e.g., adding/removing email addresses or phone numbers) with proper validation and touched-state tracking per item.
Forms requiring cross-field validation: Use cases like password confirmation, date range pickers, or conditional required fields benefit from Formik's validate function, which receives all form values and can return errors for multiple fields based on interdependent logic.
Integration with UI component libraries: Formik's field prop pattern (containing name, value, onChange, onBlur) maps cleanly to Material-UI, Ant Design, or Chakra UI input APIs, and form prop access allows custom components to trigger setFieldValue or read errors without Context wiring.
React Native mobile forms where library support is limited: Formik works identically in React Native as in web React, handling TextInput components and validation the same way, making it a go-to for teams sharing form logic across platforms.
npm install formikpnpm add formikbun add formik