Hook-based form state management for functional components, providing complete form control without component wrappers.
Primary hook for managing form state, validation, and submission in functional components.
/**
* Hook for form state management without component wrapper
* @param config - Formik configuration object
* @returns Complete formik props object with state and handlers
*/
function useFormik<Values extends FormikValues = FormikValues>(
config: FormikConfig<Values>
): FormikProps<Values>;
interface FormikConfig<Values> {
/** Initial values of the form */
initialValues: Values;
/** Form submission handler */
onSubmit: (values: Values, formikHelpers: FormikHelpers<Values>) => void | Promise<any>;
/** Yup schema or validation function */
validationSchema?: any | (() => any);
/** Custom validation function */
validate?: (values: Values) => void | object | Promise<FormikErrors<Values>>;
/** Validate on input change (default: true) */
validateOnChange?: boolean;
/** Validate on input blur (default: true) */
validateOnBlur?: boolean;
/** Validate on component mount (default: false) */
validateOnMount?: boolean;
/** Whether initial form values are valid */
isInitialValid?: boolean | ((props: any) => boolean);
/** Reset form when initialValues change */
enableReinitialize?: boolean;
/** Initial status value */
initialStatus?: any;
/** Initial errors object */
initialErrors?: FormikErrors<Values>;
/** Initial touched object */
initialTouched?: FormikTouched<Values>;
/** Reset handler */
onReset?: (values: Values, formikHelpers: FormikHelpers<Values>) => void;
}
interface FormikProps<Values> {
/** Current form values */
values: Values;
/** Current form errors */
errors: FormikErrors<Values>;
/** Fields that have been visited */
touched: FormikTouched<Values>;
/** Whether form is currently submitting */
isSubmitting: boolean;
/** Whether form is currently validating */
isValidating: boolean;
/** Top-level status object */
status?: any;
/** Number of submit attempts */
submitCount: number;
/** Whether form has been modified */
dirty: boolean;
/** Whether form is valid */
isValid: boolean;
/** Initial form values */
initialValues: Values;
/** Initial form errors */
initialErrors: FormikErrors<Values>;
/** Initial touched state */
initialTouched: FormikTouched<Values>;
/** Initial status */
initialStatus?: any;
/** Form submit handler */
handleSubmit: (e?: React.FormEvent<HTMLFormElement>) => void;
/** Form reset handler */
handleReset: (e?: React.SyntheticEvent<any>) => void;
/** Input blur handler */
handleBlur: (e: React.FocusEvent<any>) => void;
/** Input change handler */
handleChange: (e: React.ChangeEvent<any>) => void;
/** Get field props */
getFieldProps: (props: string | FieldConfig) => FieldInputProps<any>;
/** Get field meta data */
getFieldMeta: (name: string) => FieldMetaProps<any>;
/** Get field helpers */
getFieldHelpers: (name: string) => FieldHelperProps<any>;
/** Set field value */
setFieldValue: (field: string, value: any, shouldValidate?: boolean) => Promise<void | FormikErrors<Values>>;
/** Set field error */
setFieldError: (field: string, message: string | undefined) => void;
/** Set field touched state */
setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => Promise<void | FormikErrors<Values>>;
/** Set form status */
setStatus: (status?: any) => void;
/** Set form errors */
setErrors: (errors: FormikErrors<Values>) => void;
/** Set form submitting state */
setSubmitting: (isSubmitting: boolean) => void;
/** Set form touched state */
setTouched: (touched: FormikTouched<Values>, shouldValidate?: boolean) => Promise<void | FormikErrors<Values>>;
/** Set form values */
setValues: (values: React.SetStateAction<Values>, shouldValidate?: boolean) => Promise<void | FormikErrors<Values>>;
/** Validate entire form */
validateForm: (values?: any) => Promise<FormikErrors<Values>>;
/** Validate single field */
validateField: (field: string) => Promise<void> | Promise<string | undefined>;
/** Reset form to initial state */
resetForm: (nextState?: Partial<FormikState<Values>>) => void;
/** Submit form programmatically */
submitForm: () => Promise<void>;
/** Set entire Formik state */
setFormikState: (f: FormikState<Values> | ((prevState: FormikState<Values>) => FormikState<Values>), cb?: () => void) => void;
/** Register field with Formik */
registerField: (name: string, fns: { validate?: FieldValidator }) => void;
/** Unregister field from Formik */
unregisterField: (name: string) => void;
}Usage Examples:
import { useFormik } from "formik";
import * as Yup from "yup";
// Basic usage
const SignupForm = () => {
const formik = useFormik({
initialValues: {
firstName: '',
lastName: '',
email: '',
},
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 address').required('Required'),
}),
onSubmit: values => {
alert(JSON.stringify(values, null, 2));
},
});
return (
<form onSubmit={formik.handleSubmit}>
<label htmlFor="firstName">First Name</label>
<input
id="firstName"
name="firstName"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.firstName}
/>
{formik.touched.firstName && formik.errors.firstName ? (
<div>{formik.errors.firstName}</div>
) : null}
<label htmlFor="lastName">Last Name</label>
<input
id="lastName"
name="lastName"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.lastName}
/>
{formik.touched.lastName && formik.errors.lastName ? (
<div>{formik.errors.lastName}</div>
) : null}
<label htmlFor="email">Email Address</label>
<input
id="email"
name="email"
type="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
/>
{formik.touched.email && formik.errors.email ? (
<div>{formik.errors.email}</div>
) : null}
<button type="submit">Submit</button>
</form>
);
};
// Using getFieldProps for cleaner code
const LoginForm = () => {
const formik = useFormik({
initialValues: { username: '', password: '' },
onSubmit: values => console.log(values),
});
return (
<form onSubmit={formik.handleSubmit}>
<input
placeholder="Username"
{...formik.getFieldProps('username')}
/>
<input
type="password"
placeholder="Password"
{...formik.getFieldProps('password')}
/>
<button type="submit" disabled={formik.isSubmitting}>
Submit
</button>
</form>
);
};
// Async validation and submission
const AsyncForm = () => {
const formik = useFormik({
initialValues: { email: '' },
validate: async (values) => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else {
// Simulate async validation
const isAvailable = await checkEmailAvailability(values.email);
if (!isAvailable) {
errors.email = 'Email already taken';
}
}
return errors;
},
onSubmit: async (values, { setSubmitting, setStatus }) => {
try {
await submitForm(values);
setStatus({ type: 'success', message: 'Form submitted successfully!' });
} catch (error) {
setStatus({ type: 'error', message: 'Submission failed' });
} finally {
setSubmitting(false);
}
},
});
return (
<form onSubmit={formik.handleSubmit}>
<input {...formik.getFieldProps('email')} />
{formik.errors.email && <div>{formik.errors.email}</div>}
{formik.status && (
<div className={formik.status.type}>
{formik.status.message}
</div>
)}
<button type="submit" disabled={formik.isSubmitting || formik.isValidating}>
{formik.isSubmitting ? 'Submitting...' : 'Submit'}
</button>
</form>
);
};Functions for integrating with external validation libraries and handling validation errors.
/**
* Convert Yup validation errors to Formik error format
* @param yupError - Yup validation error object
* @returns Formik-compatible errors object
*/
function yupToFormErrors<Values>(yupError: any): FormikErrors<Values>;
/**
* Validate values against Yup schema
* @param values - Values to validate
* @param schema - Yup validation schema
* @param sync - Whether to run synchronously
* @param context - Validation context
* @returns Promise resolving to validation errors
*/
function validateYupSchema<T extends FormikValues>(
values: T,
schema: any,
sync?: boolean,
context?: any
): Promise<Partial<T>>;
/**
* Prepare form data for validation by handling nested objects and arrays
* @param values - Form values to prepare
* @returns Prepared values for validation
*/
function prepareDataForValidation<T extends FormikValues>(values: T): any;Usage Examples:
import { useFormik, yupToFormErrors, validateYupSchema } from "formik";
import * as Yup from "yup";
// Custom validation using Yup utilities
const FormWithCustomValidation = () => {
const schema = Yup.object({
name: Yup.string().required('Name is required'),
age: Yup.number().min(18, 'Must be 18 or older').required('Age is required'),
});
const formik = useFormik({
initialValues: { name: '', age: '' },
validate: async (values) => {
try {
await validateYupSchema(values, schema);
return {};
} catch (error) {
return yupToFormErrors(error);
}
},
onSubmit: values => console.log(values),
});
return (
<form onSubmit={formik.handleSubmit}>
<input {...formik.getFieldProps('name')} placeholder="Name" />
{formik.errors.name && <div>{formik.errors.name}</div>}
<input {...formik.getFieldProps('age')} type="number" placeholder="Age" />
{formik.errors.age && <div>{formik.errors.age}</div>}
<button type="submit">Submit</button>
</form>
);
};
// Manual error handling
const ManualValidationForm = () => {
const formik = useFormik({
initialValues: { username: '' },
onSubmit: async (values, { setFieldError, setSubmitting }) => {
try {
await submitUser(values);
} catch (error) {
if (error.field === 'username') {
setFieldError('username', error.message);
}
} finally {
setSubmitting(false);
}
},
});
const handleCheckAvailability = async () => {
if (!formik.values.username) return;
try {
const available = await checkUsernameAvailability(formik.values.username);
if (!available) {
formik.setFieldError('username', 'Username not available');
} else {
formik.setFieldError('username', undefined);
}
} catch (error) {
formik.setFieldError('username', 'Error checking availability');
}
};
return (
<form onSubmit={formik.handleSubmit}>
<input {...formik.getFieldProps('username')} placeholder="Username" />
<button type="button" onClick={handleCheckAvailability}>
Check Availability
</button>
{formik.errors.username && <div>{formik.errors.username}</div>}
<button type="submit" disabled={formik.isSubmitting}>
Submit
</button>
</form>
);
};Core TypeScript interfaces for form state management.
interface FormikState<Values> {
/** Current form values */
values: Values;
/** Current form errors */
errors: FormikErrors<Values>;
/** Fields that have been visited */
touched: FormikTouched<Values>;
/** Whether form is currently submitting */
isSubmitting: boolean;
/** Whether form is currently validating */
isValidating: boolean;
/** Top-level status object */
status?: any;
/** Number of submit attempts */
submitCount: number;
}
interface FormikComputedProps<Values> {
/** Whether form has been modified from initial values */
readonly dirty: boolean;
/** Whether form passes validation */
readonly isValid: boolean;
/** Initial form values */
readonly initialValues: Values;
/** Initial form errors */
readonly initialErrors: FormikErrors<Values>;
/** Initial touched state */
readonly initialTouched: FormikTouched<Values>;
/** Initial status value */
readonly initialStatus?: any;
}
interface FormikHelpers<Values> {
/** Set top-level status */
setStatus: (status?: any) => void;
/** Set form errors object */
setErrors: (errors: FormikErrors<Values>) => void;
/** Set form submitting state */
setSubmitting: (isSubmitting: boolean) => void;
/** Set form touched state */
setTouched: (touched: FormikTouched<Values>, shouldValidate?: boolean) => Promise<void | FormikErrors<Values>>;
/** Set entire form values */
setValues: (values: React.SetStateAction<Values>, shouldValidate?: boolean) => Promise<void | FormikErrors<Values>>;
/** Set individual field value */
setFieldValue: (field: string, value: any, shouldValidate?: boolean) => Promise<void | FormikErrors<Values>>;
/** Set individual field error */
setFieldError: (field: string, message: string | undefined) => void;
/** Set individual field touched state */
setFieldTouched: (field: string, isTouched?: boolean, shouldValidate?: boolean) => Promise<void | FormikErrors<Values>>;
/** Validate entire form */
validateForm: (values?: any) => Promise<FormikErrors<Values>>;
/** Validate single field */
validateField: (field: string) => Promise<void> | Promise<string | undefined>;
/** Reset form to initial or provided state */
resetForm: (nextState?: Partial<FormikState<Values>>) => void;
/** Submit form programmatically */
submitForm: () => Promise<void>;
/** Set entire Formik state */
setFormikState: (f: FormikState<Values> | ((prevState: FormikState<Values>) => FormikState<Values>), cb?: () => void) => void;
}
interface FormikHandlers {
/** Form submit event handler */
handleSubmit: (e?: React.FormEvent<HTMLFormElement>) => void;
/** Form reset event handler */
handleReset: (e?: React.SyntheticEvent<any>) => void;
/** Input blur event handler */
handleBlur: (e: React.FocusEvent<any>) => void;
/** Input change event handler */
handleChange: (e: React.ChangeEvent<any>) => void;
/** Get field input props */
getFieldProps: (props: string | FieldConfig) => FieldInputProps<any>;
/** Get field metadata */
getFieldMeta: (name: string) => FieldMetaProps<any>;
/** Get field helper functions */
getFieldHelpers: (name: string) => FieldHelperProps<any>;
}Type checking and object manipulation utilities for advanced form scenarios and custom integrations.
/**
* Check if value is a function
* @param obj - Value to check
* @returns True if value is a function
*/
function isFunction(obj: any): obj is Function;
/**
* Check if value is an object
* @param obj - Value to check
* @returns True if value is an object
*/
function isObject(obj: any): obj is Object;
/**
* Check if value is a string
* @param obj - Value to check
* @returns True if value is a string
*/
function isString(obj: any): obj is string;
/**
* Check if value is an integer
* @param obj - Value to check
* @returns True if value is an integer
*/
function isInteger(obj: any): boolean;
/**
* Check if value is NaN
* @param obj - Value to check
* @returns True if value is NaN
*/
function isNaN(obj: any): boolean;
/**
* Check if value is an empty array
* @param value - Value to check
* @returns True if value is an empty array
*/
function isEmptyArray(value?: any): boolean;
/**
* Check if React children are empty
* @param children - React children to check
* @returns True if children are empty
*/
function isEmptyChildren(children: any): boolean;
/**
* Check if value is Promise-like
* @param value - Value to check
* @returns True if value has then method
*/
function isPromise(value: any): value is PromiseLike<any>;
/**
* Check if value is a React input event
* @param value - Value to check
* @returns True if value is a React SyntheticEvent
*/
function isInputEvent(value: any): value is React.SyntheticEvent<any>;
/**
* Get the currently active DOM element
* @param doc - Document object (defaults to global document)
* @returns Currently active element or null
*/
function getActiveElement(doc?: Document): Element | null;
/**
* Get nested object value by path
* @param obj - Object to traverse
* @param key - Path string or array of keys
* @param def - Default value if path not found
* @returns Value at path or default value
*/
function getIn(obj: any, key: string | string[], def?: any): any;
/**
* Set nested object value by path
* @param obj - Object to modify
* @param path - Path string to set value at
* @param value - Value to set
* @returns Modified object
*/
function setIn(obj: any, path: string, value: any): any;
/**
* Set values in nested object structure
* @param object - Object to modify
* @param value - Value to set throughout structure
* @returns Modified object with values set
*/
function setNestedObjectValues<T>(object: any, value: any): T;Usage Examples:
import { getIn, setIn, isFunction, isPromise } from "formik";
// Object path manipulation
const user = {
profile: {
contact: {
email: 'user@example.com'
}
}
};
// Get nested value
const email = getIn(user, 'profile.contact.email'); // 'user@example.com'
const phone = getIn(user, 'profile.contact.phone', 'No phone'); // 'No phone'
// Set nested value
const updatedUser = setIn(user, 'profile.contact.phone', '555-1234');
// Type checking
const validate = (value) => {
if (!isString(value)) {
return 'Value must be a string';
}
if (isFunction(value)) {
return 'Functions are not allowed';
}
// Handle async validation
if (isPromise(value)) {
return value.then(result => validate(result));
}
return undefined;
};
// Custom field component using utilities
const AdvancedField = ({ name, ...props }) => {
const [field, meta, helpers] = useField(name);
const handleChange = (e) => {
if (isInputEvent(e)) {
field.onChange(e);
} else {
// Handle programmatic value changes
helpers.setValue(e);
}
};
return (
<input
{...field}
{...props}
onChange={handleChange}
/>
);
};