final-form, formik, rc-field-form, and react-hook-form are tools for building forms in React applications. They handle user input, validation, and submission state but use different technical approaches. react-hook-form focuses on uncontrolled inputs for performance. formik uses controlled components with a centralized state object. final-form is a framework-neutral engine often paired with React bindings. rc-field-form powers Ant Design forms but works standalone with a field-based architecture.
Building forms in React involves managing state, validation, and user feedback. The libraries final-form, formik, rc-field-form, and react-hook-form solve these problems with different architectures. Understanding their core models helps you pick the right tool for your project constraints.
The way each library tracks input values defines its performance profile and code style.
react-hook-form uses uncontrolled inputs by default.
// react-hook-form: Uncontrolled via refs
const { register } = useForm();
return <input {...register('firstName')} />;
formik uses controlled components.
values object in state.// formik: Controlled via state
const { values, handleChange } = useFormik();
return <input name="firstName" value={values.firstName} onChange={handleChange} />;
final-form (via react-final-form) uses a subscription model.
// final-form: Subscription based
<Field name="firstName">
{({ input }) => <input {...input} />}
</Field>
rc-field-form uses an internal store with field registration.
// rc-field-form: Field registration
<Form>
<Field name="firstName">
<input />
</Field>
</Form>
Validation logic determines how you define rules for user input.
react-hook-form supports schema libraries or native functions.
validate option inside the register function.// react-hook-form: Schema or inline
useForm({ resolver: yupResolver(schema) });
// Or
register('email', { validate: (v) => v.includes('@') });
formik relies heavily on external schema libraries.
errors object.// formik: Validation function
useFormik({
validate: (values) => {
const errors = {};
if (!values.email) errors.email = 'Required';
return errors;
}
});
final-form uses a validator function per field or form.
// final-form: Field validator
<Field name="email" validate={required} />
rc-field-form uses rules objects on the Field component.
// rc-field-form: Rules object
<Field name="email" rules={[{ required: true }]}>
<input />
</Field>
The API shape affects how you compose your form UI.
react-hook-form is hook-centric.
useForm at the top of your component.// react-hook-form: Hook usage
const { register, handleSubmit } = useForm();
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('name')} />
</form>
formik mixes hooks and components.
useFormik hook or the <Formik> component.<Form> and <Field> components.// formik: Component usage
<Formik initialValues={{ name: '' }} onSubmit={onSubmit}>
<Form>
<Field name="name" />
</Form>
</Formik>
final-form relies on render props components.
<Form> component takes a render function.// final-form: Render props
<Form onSubmit={onSubmit}>
{({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field name="name" component="input" />
</form>
)}
</Form>
rc-field-form uses a strict Component hierarchy.
<Form> wraps <Field> components.// rc-field-form: Hierarchy
<Form onFinish={onFinish}>
<Field name="name">
<input />
</Field>
</Form>
Your existing stack influences which tool integrates smoothly.
react-hook-form is framework neutral within React.
// react-hook-form: Any UI library
<input {...register('id')} className="custom-input" />
formik is also UI library neutral.
// formik: Any UI library
<input name="id" value={values.id} onChange={handleChange} />
final-form is truly framework neutral.
react-final-form wrapper package.// final-form: Core logic (JS)
const form = createForm({ onSubmit, validate });
// React needs react-final-form wrapper
rc-field-form is built for Ant Design.
// rc-field-form: AntD aligned
<Field name="id">
<Input /> // Typically AntD Input component
</Field>
Despite different architectures, these tools solve the same core problems.
// react-hook-form
handleSubmit(onSubmit)
// formik
handleSubmit(onSubmit)
// final-form
onSubmit={handleSubmit}
// rc-field-form
onFinish={onSubmit}
// react-hook-form
{errors.name && <span>{errors.name.message}</span>}
// formik
{errors.name && <span>{errors.name}</span>}
// final-form
{meta.error && <span>{meta.error}</span>}
// rc-field-form
<Field rules={[{ required: true }]}>
{/* Error rendered automatically or via context */}
</Field>
// react-hook-form
formState.isDirty
// formik
formikProps.dirty
// final-form
meta.dirty
// rc-field-form
Field context provides touched status
| Feature | react-hook-form | formik | final-form | rc-field-form |
|---|---|---|---|---|
| State Model | Uncontrolled (Refs) | Controlled (State) | Subscription | Internal Store |
| Primary API | Hooks (useForm) | Hook or Component | Render Props | Components |
| Validation | Schema or Inline | Schema or Function | Function | Rules Object |
| Best For | Performance | Simplicity | Cross-Framework | Ant Design Users |
| Re-renders | Minimal | Per Keystroke | Scoped | Scoped |
react-hook-form is the current standard for new React projects.
formik remains viable for simpler forms.
final-form fits multi-framework teams.
rc-field-form is for Ant Design ecosystems.
Final Thought: Forms are complex ā pick the tool that matches your performance needs and UI stack. For most React teams today, react-hook-form provides the best balance of speed and developer experience.
Choose react-hook-form if you want maximum performance with minimal re-renders in a React application. It is ideal for large forms or dynamic fields where input latency matters. The API relies heavily on React hooks and uncontrolled components. It has the largest community momentum and frequent updates for modern React patterns.
Choose formik if you prefer a straightforward, controlled component model that keeps all form state in one place. It is suitable for projects already using Yup for validation schemas. Be aware that development pace has slowed compared to newer tools. It remains a stable choice for simple to medium complexity forms where performance is not the top priority.
Choose final-form if you need a form engine that works across different UI libraries like React, Vue, or Angular. It is best for teams maintaining multiple frameworks who want shared validation logic. Note that for React projects, you will need the react-final-form binding which adds some boilerplate. It offers fine-grained subscription updates to avoid unnecessary re-renders.
Choose rc-field-form if you are building an application using Ant Design components or need its specific field management architecture. It is tightly integrated with the Ant Design ecosystem. Standalone usage is possible but less common outside of AntD projects. It excels at managing complex nested field structures typical in enterprise dashboards.
Get started | API | Form Builder | FAQs | Examples
npm install react-hook-form
import { useForm } from 'react-hook-form';
function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register('firstName')} />
<input {...register('lastName', { required: true })} />
{errors.lastName && <p>Last name is required.</p>}
<input {...register('age', { pattern: /\d+/ })} />
{errors.age && <p>Please enter number for age.</p>}
<input type="submit" />
</form>
);
}
Weāre incredibly grateful to these kind and generous sponsors for their support!
Thank you to our previous sponsors for your generous support!
Thanks go to all our backers! [Become a backer].
Thanks go to these wonderful people! [Become a contributor].
Documentation website supported and backed by Vercel