Introduction
As front-end developers, forms play a crucial role in our daily work. Rather than reinventing the wheel and writing forms from scratch every time, it's important to understand the various libraries available to streamline and simplify the form-building process.
In this article, we will explore top React form libraries that can help us create efficient and user-friendly forms with ease.
1. SurveyJS React Form Library
SurveyJS React Form Library is a tool for React applications that helps create dynamic forms on the client side. It uses JSON objects to define the structure and behaviour of forms.
It's one of the popular open-source form libraries, with 3.9k stars on GitHub and 17.4k user downloads on npm.
Features:
- Dynamic forms for JavaScript application
- 20+ built-in question types and support for custom question types
- Built-in themes and CSS customization
- Answer validation
- TypeScript support
- Integration with any backend framework (examples for PHP, - NodeJS, and ASP.NET included)
- Compatibility with any server + database combination Third-party component integration
How to use
Here are the steps to add a React Survey form to a React application:
- Install the survey-react-ui npm Package
- Configure Styles
- Create a Model
- Render the Form
- Handle Form Completion
This will result in a form similar to this one:
import { useCallback } from "react";
import "survey-core/defaultV2.min.css";
import { Model } from "survey-core";
import { Survey } from "survey-react-ui";
const surveyJson = {
elements: [
{
name: "FirstName",
title: "Enter your first name:",
type: "text",
},
{
name: "LastName",
title: "Enter your last name:",
type: "text",
},
],
};
function App() {
const survey = new Model(surveyJson);
survey.focusFirstQuestionAutomatic = false;
const alertResults = useCallback((sender) => {
const results = JSON.stringify(sender.data);
alert(results);
}, []);
survey.onComplete.add(alertResults);
return <Survey model={survey} />;
}
export default App;
2. React Hook Form
React Hook Form - Performant, flexible and extensible forms with easy-to-use validation. It's one of the most popular form libraries, with 33.5k stars on GitHub and 3.1 million user downloads on npm.
Features:
- Performance: Minimizes the number of re-renders, reduces validation computation, and faster mounting.
- Super Light: Package size matters. React Hook Form is a tiny library without any dependencies.
- HTML standard: Embraces native HTML form validation
- Adoptable: it can be easily adopted without other dependencies.
- Support Yup, Zod, AJV, Superstruct, Joi and others
How to Install:
npm i react-hook-form
How to use:
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>
);
}
The code above is an example usage of the useForm
hook from the react-hook-form
library in a React component.
The useForm
hook is used to manage form state and validation.
In the example, the register
function is used to register the input fields in the form, and returns the necessary props for each input. The handleSubmit
function is passed to the onSubmit
prop of the form and it is responsible for handling the form submission.
The formState
object returned by useForm
includes the current state of the form, including any errors that have been detected during validation.
The example defines a form with three input fields; first name, last name, and age. The last name input is required, and the age input requires a numeric value.
If the user leaves the last name field empty or enters a non-numeric value for the age field, an error message is displayed.
When the form is submitted, the handleSubmit
function logs the form data to the console.
3. Formik
Formik allows us to build complex forms easily. It's also one of the most popular open-source form libraries for React and React Native. It has 32k stars on GitHub and 2.4 million user downloads on npm.
Features:
- Declarative: Formik handles the repetitive and annoying stuff—keeping track of values/errors/visited fields, orchestrating validation, and handling submission.
- Intuitive: Formik makes debugging, testing, and reasoning about our forms a breeze by staying within the core React framework and away from magic.
- Adoptable: Formik does not use external state management libraries like Redux or MobX.
How to Install:
npm i formik
How to use:
// Render Prop
import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
const Basic = () => (
<div>
<h1>Any place in your app!</h1>
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
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 address';
}
return errors;
}}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
setSubmitting(false);
}, 400);
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="email" name="email" />
<ErrorMessage name="email" component="div" />
<Field type="password" name="password" />
<ErrorMessage name="password" component="div" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
</div>
);
export default Basic;
The usage example above defines a component that renders a form with an email and password input, and a submit button.
The Formik component wraps the form and provides functionality for handling form state, validation, and submission.
The initialValues
prop defines the initial values for the form inputs, and the validate
function is used for form validation. If any errors are detected, they are returned as an object.
The onSubmit
function is called when the form is submitted, and it can be used to perform any necessary actions, such as sending data to a server or updating the application state.
The Formik component takes a render prop that is used to define the form fields and error messages. The Field
component is used to define the form input fields, and the ErrorMessage
component is used to display any validation errors.
Finally, the submit button is disabled when the form is submitting to prevent multiple submissions.
This is just one example of how Formik can be used in a React application to manage forms with complex validation and submission logic.
React Hook Forms Vs Formik
React Hook Form | Formik | |
---|---|---|
Component | Uncontrolled & Controlled | Controlled |
API | Hooks | Components + Hooks |
Package size | Smallreact-hook-form@7.27.0 **8.5KB**
|
Mediumformik@2.1.4 **15KB**
|
Validation | Built-in, Yup, Zod, Joi, Superstruct and allow custom validation. | Custom or Yup |
Learning curve | Low to Medium | Medium |
4. rc-field-form
rc-field-form- React Performance First Form Component. It has 783 stars on GitHub and 885k user downloads on npm.
Features:
- Support react.js and even react-native
- Validate fields with async-validator
How to Install:
npm i rc-field-form
How to Use:
import Form, { Field } from 'rc-field-form';
const Input = ({ value = "", ...props }) => <input value={value} {...props} />;
const Demo = () => {
return (
<Form
onFinish={(values) => {
console.log("Finish:", values);
}}
>
<Field name="username">
<Input placeholder="Username" />
</Field>
<Field name="password">
<Input placeholder="Password" />
</Field>
<button>Submit</button>
</Form>
);
};
export default Demo;
The usage example above defines a component called Demo
that renders a form with two input fields for a username and password.
The Form
component wraps the form and provides functionality for handling form state, validation, and submission. The onFinish
prop is called when the form is submitted and receives an object with the form values.
The Field
component is used to define the form fields and provide validation rules. The name
prop is used to define the name of the field, and any custom validation rules can be defined using the rules
prop.
The Input
component is a custom input field that receives the value
prop and any additional props. It is used to define the input fields for the form.
Finally, the submit button is defined outside of the Field
components and is used to trigger the form submission.
This is just one example of how rc-field-form can be used in a React application to manage form fields and handle the form submission.
5. React Final Form
React Final Form - High-performance subscription-based form state management for React. It follows the observer design pattern in which components subscribe to events as they occur. It does not re-render the entire form, only the fields that have subscribed to re-render. It has 7.2k stars on GitHub and 364k user downloads on npm.
Features:
- Zero dependencies (that affect the bundle size)
- Only peer dependencies: React and React Final Form
- Opt-in subscriptions - only update on the state we need!
How to Install:
npm i react-final-form
How to Use:
import { Form, Field } from 'react-final-form'
const MyForm = () => (
<Form
onSubmit={onSubmit}
validate={validate}
render={({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<h2>Simple Default Input</h2>
<div>
<label>First Name</label>
<Field name="firstName" component="input" placeholder="First Name" />
</div>
<h2>An Arbitrary Reusable Input Component</h2>
<div>
<label>Interests</label>
<Field name="interests" component={InterestPicker} />
</div>
<h2>Render Function</h2>
<Field
name="bio"
render={({ input, meta }) => (
<div>
<label>Bio</label>
<textarea {...input} />
{meta.touched && meta.error && <span>{meta.error}</span>}
</div>
)}
/>
<h2>Render Function as Children</h2>
<Field name="phone">
{({ input, meta }) => (
<div>
<label>Phone</label>
<input type="text" {...input} placeholder="Phone" />
{meta.touched && meta.error && <span>{meta.error}</span>}
</div>
)}
</Field>
<button type="submit">Submit</button>
</form>
)}
/>
)
The code above is an example of using React Final Form library to create a form with various types of fields such as text input, reusable custom component, and render functions. The form component takes in an onSubmit
function and a validate function to handle form submission and validation respectively. The Field component is used to create each field, and it can accept a component prop to render the field with a custom component or a render prop to render the field with a custom function. The input value and state are managed by the library, and any validation errors are displayed when the user interacts with the form.
rc-field-form Vs React Final Form
rc-field-form | React Final Form | |
---|---|---|
Component | A component library for building forms in React. | A library for building forms in React. |
API | It provides Form, FormItem, and other form components that can be used to build a form. | It provides a <Form> component and a <Field> component that can be used to build a form. |
Package size | The package size of RC-Field-Form is around 105 KB. | The package size of React Final Form is around 38 KB. |
Validation | It provides built-in validation rules, such as required, pattern, and maxLength. It also allows custom validation rules. | It provides validation through a validation function, which can be passed as a prop to the <Field> component. It also allows custom validation functions. |
Learning curve | It provides good documentation and examples to get started. | It also has good documentation and examples to get started. |
6. react-credit-cards
react-credit-cards- A sleek credit card component for React. It has 2.4k stars on GitHub and 27.9k user downloads on npm.
Features:
- react-credit-cards support all credit card issuers available in Payment plus Hipercard (a Brazilian credit card).
How to Install:
npm i react-credit-cards
How to Use:
import React from 'react';
import Cards from 'react-credit-cards';
export default class PaymentForm extends React.Component {
state = {
cvc: '',
expiry: '',
focus: '',
name: '',
number: '',
};
handleInputFocus = (e) => {
this.setState({ focus: e.target.name });
}
handleInputChange = (e) => {
const { name, value } = e.target;
this.setState({ [name]: value });
}
render() {
return (
<div id="PaymentForm">
<Cards
cvc={this.state.cvc}
expiry={this.state.expiry}
focused={this.state.focus}
name={this.state.name}
number={this.state.number}
/>
<form>
<input
type="tel"
name="number"
placeholder="Card Number"
onChange={this.handleInputChange}
onFocus={this.handleInputFocus}
/>
...
</form>
</div>
);
}
}
The code above is an example of a simple credit card payment form in React, using the react-credit-cards
library to display the credit card as it's being filled out. The form includes inputs for the card number, expiration date, cardholder name, and CVC code. The state of the form is managed in the component's state object, with handleInputFocus
and handleInputChange
methods to update the state and keep track of the currently focused input field. When the form is submitted, the data can be sent to a backend for processing.
7. formsy-react
formsy-react- A form input builder and validator for React. It has 761 stars on GitHub and 25k user downloads on npm.
Features:
- Build any form element components. Not just traditional inputs, but anything we want, and get that validation for free
- Add validation rules and use them with simple syntax
- Use handlers for different states of our form. (onSubmit, onValid, etc.)
- Pass external errors to the form to invalidate elements (E.g. a response from a server)
- Dynamically add form elements to our form, and they will register/unregister to the form
How to Install:
npm i formsy-react
How to Use:
// MyInput.js
import { withFormsy } from 'formsy-react';
import React from 'react';
class MyInput extends React.Component {
constructor(props) {
super(props);
this.changeValue = this.changeValue.bind(this);
}
changeValue(event) {
// setValue() will set the value of the component, which in
// turn will validate it and the rest of the form
// Important: Don't skip this step. This pattern is required
// for Formsy to work.
this.props.setValue(event.currentTarget.value);
}
render() {
// An error message is passed only if the component is invalid
const errorMessage = this.props.errorMessage;
return (
<div>
<input onChange={this.changeValue} type="text" value={this.props.value || ''} />
<span>{errorMessage}</span>
</div>
);
}
}
export default withFormsy(MyInput);
The code above defines a custom input component MyInput
using formsy-react
library. The withFormsy
higher-order component is used to wrap the input component to enable it to work with formsy-react
.
The component defines a changeValue
method that sets the value of the input component and triggers the form validation. The render
method returns the input element along with an error message, which is displayed only when the component is invalid.
This code can be used to create custom input components with validation capabilities using formsy-react
.
react-credit-cards Vs formsy-react
react-credit-cards | formsy-react | |
---|---|---|
Component | A component library for displaying credit card input fields and validating credit card information. | A library for building forms in React. |
API | It provides a single **<Cards>** component that can be used to display credit card input fields. It also provides props for customization. |
It provides a <Form> component and a <Field> component that can be used to build a form. |
Package size | The package size of React Credit Cards is around 14 KB. | The package size of Formsy React is around 25 KB. |
Validation | It provides built-in validation rules for credit card number, expiration date, and security code. It also allows custom validation rules. | It provides validation through a validation function, which can be passed as a prop to the <Field> component. It also allows custom validation functions. |
Learning curve | good documentation and examples to get started. | It also has good documentation and examples to get started. |
8. react-form
react-form- Hooks for managing form state and validation in React. It has 2.5k stars on GitHub and 14.3k user downloads on npm.
Features:
- Built with React hooks for React hooks
- Highly practical validation API with 1st-class asynchronous support
- Built-in validation debouncing with auto cancellation for stale validations
- Field Scoping for deeply nested form values
- No-nonsense meta-management for both forms and form fields
- Fully memorized for frequent and fast rerenders
- Flexible form API at the field, scope, and form levels
How to Install:
npm i react-form
How to Use:
import React from "react";
import ReactDOM from "react-dom";
import { useForm, useField } from "react-form";
async function sendToFakeServer(values) {
await new Promise(resolve => setTimeout(resolve, 1000));
return values;
}
function validateAddressStreet(value) {
if (!value) {
return "A street is required";
}
return false;
}
async function validateName(name, instance) {
if (!name) {
return "A name is required";
}
return instance.debounce(async () => {
console.log("checking name");
await new Promise(resolve => setTimeout(resolve, 1000));
// All names are valid, so return a false error
return false;
}, 500);
}
function NameField() {
const {
meta: { error, isTouched, isValidating },
getInputProps
} = useField("name", {
validate: validateName
});
return (
<>
<input {...getInputProps()} />{" "}
{isValidating ? (
<em>Validating...</em>
) : isTouched && error ? (
<em>{error}</em>
) : null}
</>
);
}
function AddressStreetField() {
const {
meta: { error, isTouched, isValidating },
getInputProps
} = useField("address.street", {
validate: validateAddressStreet
});
return (
<>
<input {...getInputProps()} />{" "}
{isValidating ? (
<em>Validating...</em>
) : isTouched && error ? (
<em>{error}</em>
) : null}
</>
);
}
function MyForm() {
// Use the useForm hook to create a form instance
const {
Form,
meta: { isSubmitting, canSubmit }
} = useForm({
onSubmit: async (values, instance) => {
// onSubmit (and everything else in React Form)
// has async support out-of-the-box
await sendToFakeServer(values);
console.log("Huzzah!");
},
debugForm: true
});
return (
<Form>
<div>
<label>
Name: <NameField />
</label>
</div>
<div>
<label>
Address Street: <AddressStreetField />
</label>
</div>
<div>
<button type="submit" disabled={!canSubmit}>
Submit
</button>
</div>
<div>
<em>{isSubmitting ? "Submitting..." : null}</em>
</div>
</Form>
);
}
function App() {
return <MyForm />;
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
The usage example above is a React code that uses the react-form
library to handle form validation and submission. It creates a form instance using the useForm
hook and defines two form fields (NameField
and AddressStreetField
) using the useField
hook, each with its own validation function.
The MyForm
component renders the form and handles submission. When the form is submitted, it sends the form data to a fake server using sendToFakeServer
function. It also displays an error message if the form data is invalid, and displays a "Submitting..." message while the form is being submitted. Finally, the **App**
component renders the MyForm
component.
9. uniforms
uniforms- A React library for building forms from any schema. It has 1.7k stars on GitHub and 13.9k user downloads on npm.
Features:
- Automatic forms generation
- Fields capable of rendering every schema
- Helper with creating custom fields with one line
- Inline and asynchronous form validation
- Integrations with various schemas
- Wide range of themes:
How to Install:
npm i uniforms
How to Use:
import React from 'react';
import { AutoForm } from 'uniforms-semantic';
import { bridge as schema } from './GuestSchema';
export function GuestFormBasic() {
return <AutoForm schema={schema} onSubmit={console.log} />;
}
The code above creates a basic form using the **uniforms-semantic**
library with a predefined schema and a console log statement to display the form data when it is submitted.
react-form Vs uniforms
react-form | uniforms | |
---|---|---|
Component | Built with React hooks for React hooks | A library for building forms in React. |
API | Flexible form API at the field, scope, and form levels | It provides a set of components that can be used to build a form, including <AutoForm> , <LongTextField> , <SelectField> , and more. |
Package size | The package size of React Form is around 14 KB. | The package size of Uniforms is around 72 KB. |
Validation | Built-in validation debouncing with auto cancellation for stale validations | It provides a simple schema-based validation system, which can be used to validate form inputs. It also allows custom validation functions. |
Learning curve | good documentation and examples to get started. | good documentation and examples to get started. |
10. MobX React Form
MobX React Form- Reactive MobX Form State Management. It has 1.1k stars on GitHub and 7.2k user downloads on npm.
Features:
- Extensible Validation Plugins.
- Sync & Async Validation (w/ Promises & automatic errors).
- Nested Fields (w/ Serialization & Validation).
- Nested Forms (w/ Nested Submission & Validation Hooks).
- Event Hooks, Event Handlers & Validation Hooks
- Observers & Interceptors
- Bindings for custom Components.
- Support for Material UI, React Widgets, React Select & more.
- Dedicated DevTools Package.
How to Install:
npm i mobx-react-form
How to Use:
import React from 'react';
import { observer } from 'mobx-react';
export default observer(({ myForm }) => (
<form onSubmit={myForm.onSubmit}>
<label htmlFor={myForm.$('email').id}>
{myForm.$('email').label}
</label>
<input {...myForm.$('email').bind()} />
<p>{myForm.$('email').error}</p>
{/* ... other inputs ... */}
<button type="submit" onClick={myForm.onSubmit}>Submit</button>
<button type="button" onClick={myForm.onClear}>Clear</button>
<button type="button" onClick={myForm.onReset}>Reset</button>
<p>{myForm.error}</p>
</form>
));
The code above creates a form component using React and the mobx-react
library. The observer
function is used to make the component reactive to changes in the form state managed by MobX.
The form component renders a form element with input fields generated based on the myForm
object passed as a prop. The myForm
object is expected to have methods and properties provided by MobX to handle form validation, submission, clearing, and resetting.
The input fields are generated using the bind
method of the $
object which generates the necessary properties and handlers for the input field to be reactive to changes.
The form also includes buttons for submission, clearing, and resetting the form. The myForm.onSubmit
, myForm.onClear
, and myForm.onReset
methods are called respectively when the buttons are clicked.
11. HouseForm
HouseForm - Field-First React Form Validation, where our form validation and UI code live harmoniously. It has 173 stars on GitHub and 191 user downloads on npm.
Features:
- Field First: Consolidate our UI and validation logic in one location - our fields.
- Headless & runtime agnostic: Use HouseForm in any React-supported environment, from native apps to the CLI.
- Zod Powered: Easily set up complex validations for our form fields.
- Flexible API: Mix and match which validation methods work best per field.
- Lightweight: HouseForm has a smaller bundle of less than 4KB GZIP.
- Fast: Our benchmarks have us on par or faster than common alternatives.
How to Install:
npm i houseform
How to Use:
import {Form} from 'houseform';
const App = () => (
<Form onSubmit={() => {}}>
{({submit}) => <button onClick={submit}>Submit</button>}
</Form>
)
The App
component renders the Form
component with an onSubmit
prop set to an empty arrow function.
The Form
component accepts a function as a child with a submit
argument provided. This function returns a button
element with an onClick
event handler set to the submit
function.
When the button is clicked, it triggers the submit
function provided by the Form
component to handle the form submission logic.
HouseForm Vs MobX React Form
HouseForm | MobX React Form | |
---|---|---|
Component | HouseForm uses uncontrolled components | Uncontrolled & Controlled |
API | Flexible API | It provides a set of components that can be used to build a form, including <Form> , <Field> , and <Errors>
|
Package size | HouseForm is 13.5kb unminified without GZIP | 110.6 kB Minified and 28.7kb Minified + GZIPPED |
Validation | HouseForm uses Zod for validation | Extensibles Validation Plugins. |
Learning curve | good documentation and examples to get started. | good documentation and examples to get started. |
Conclusion
Thanks for checking out this piece! Hope it was helpful for your coding journey. Keep on coding, and have fun!
Top comments (5)
Comming from Angular and used to its Reactive Forms I found this reactjs library that is inspired from Reactive Froms called bietkul/react-reactive-form.
I would like to introduce EasyJsonForm. You can play with an interactive demo at: ricardolima.xyz/easyjsonform/
Sure! I will try it out and give my feedback @ricardolimaio
Any advice, thoughts? This leaves the reader wondering "okay now what" ...
Formik looks abandoned... Last release 2y ago, last update update on blog 3y ago.