--- name: formik description: Manages React form state with Formik using validation, field arrays, and form context. Use when building complex forms in React, handling form submission, or integrating with Yup validation. --- # Formik Form state management library for React with built-in validation, submission handling, and field management. ## Quick Start ```bash npm install formik yup ``` ```tsx import { Formik, Form, Field, ErrorMessage } from 'formik'; import * as Yup from 'yup'; const schema = Yup.object({ email: Yup.string().email('Invalid email').required('Required'), password: Yup.string().min(8, 'Too short').required('Required'), }); function LoginForm() { return ( { console.log(values); setSubmitting(false); }} > {({ isSubmitting }) => (
)}
); } ``` ## useFormik Hook ```tsx import { useFormik } from 'formik'; function Form() { const formik = useFormik({ initialValues: { email: '', password: '', }, validationSchema: schema, onSubmit: (values) => { console.log(values); }, }); return (
{formik.touched.email && formik.errors.email && (
{formik.errors.email}
)} {formik.touched.password && formik.errors.password && (
{formik.errors.password}
)}
); } ``` ## Field Component ### Basic Fields ```tsx ``` ### With Custom Component ```tsx {({ field, meta }) => (
{meta.touched && meta.error && {meta.error}}
)}
``` ### Custom Input Component ```tsx const TextInput = ({ label, ...props }) => { const [field, meta] = useField(props); return (
{meta.touched && meta.error &&
{meta.error}
}
); }; // Usage ``` ## Form Component ```tsx
{/* Form fields */}
``` Or with render prop: ```tsx {(formikProps) => (
{/* Access formik state */}
)}
``` ## Validation ### With Yup ```tsx import * as Yup from 'yup'; const validationSchema = Yup.object({ firstName: Yup.string() .max(15, 'Must be 15 characters or less') .required('Required'), lastName: Yup.string() .max(20, 'Must be 20 characters or less') .required('Required'), email: Yup.string() .email('Invalid email') .required('Required'), }); ``` ### Custom Validate Function ```tsx { const errors = {}; if (!values.email) { errors.email = 'Required'; } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) { errors.email = 'Invalid email'; } return errors; }} ... /> ``` ### Field-Level Validation ```tsx const validateUsername = async (value) => { if (!value) return 'Required'; const taken = await checkUsername(value); if (taken) return 'Username taken'; }; ``` ## Field Arrays ```tsx import { FieldArray } from 'formik'; {({ values }) => (
{({ push, remove }) => (
{values.friends.map((friend, index) => (
))}
)}
)}
``` ### Array of Objects ```tsx {({ values }) => ( {({ push, remove }) => ( <> {values.contacts.map((contact, index) => (
))} )}
)}
``` ## Formik Context ### useFormikContext ```tsx import { useFormikContext } from 'formik'; function SubmitButton() { const { isSubmitting, isValid } = useFormikContext(); return ( ); } ``` ### Accessing Form State ```tsx function FormDebug() { const { values, errors, touched, isValid, dirty } = useFormikContext(); return (
      {JSON.stringify({ values, errors, touched, isValid, dirty }, null, 2)}
    
); } ``` ## Form State ### Formik Props ```tsx {({ // Values values, // Form values initialValues, // Initial values errors, // Validation errors touched, // Touched fields // Status isSubmitting, // Submit in progress isValid, // No validation errors isValidating, // Validation in progress dirty, // Values changed from initial // Handlers handleSubmit, // Form submit handler handleChange, // Input change handler handleBlur, // Input blur handler handleReset, // Reset form // Helpers setFieldValue, // Set specific field setFieldTouched, // Mark field as touched setFieldError, // Set field error setValues, // Set all values setErrors, // Set all errors setTouched, // Set all touched setStatus, // Set form status setSubmitting, // Set submitting state resetForm, // Reset to initial validateForm, // Trigger validation validateField, // Validate specific field // Getters getFieldProps, // Get field props helper getFieldMeta, // Get field meta (error, touched) getFieldHelpers, // Get field helpers }) => (
...
)}
``` ## Submission ### Basic Submit ```tsx { submitToServer(values).then(() => { setSubmitting(false); }); }} ... /> ``` ### Async Submit ```tsx { try { await api.submit(values); resetForm(); setStatus({ success: true }); } catch (error) { setStatus({ error: error.message }); } finally { setSubmitting(false); } }} ... /> ``` ### With Server Errors ```tsx { try { await api.submit(values); } catch (error) { if (error.validationErrors) { setErrors(error.validationErrors); } } }} ... /> ``` ## Enable/Disable Reinitialize ```tsx ``` ## TypeScript ```tsx interface FormValues { email: string; password: string; } const initialValues: FormValues = { email: '', password: '', }; initialValues={initialValues} onSubmit={(values: FormValues) => { console.log(values.email); }} ... /> ``` ### Typed Custom Field ```tsx import { useField, FieldHookConfig } from 'formik'; interface TextInputProps extends FieldHookConfig { label: string; } const TextInput: React.FC = ({ label, ...props }) => { const [field, meta] = useField(props); return (
{meta.touched && meta.error &&
{meta.error}
}
); }; ``` See [references/patterns.md](references/patterns.md) for advanced patterns and recipes.