
React libraries for building forms and surveys
Written byHussain Arif✏️
While building forms in React can be straightforward, managing them can become complex. For example, without relying on a form library, a developer has to:
- Handle validation: For example, with every
onChange
oronSubmit
event, we have to tell React to check if a certain field matches the given criteria - Handle submissions: If a user wants to sign up for our app, we have to check if their email is present in the database, and then handle the situation from there
- Considerperformance: Sometimes, rendering complex components or using complex validation logic in our forms might lead to performance degradation
To mitigate challenges like these, we can use a form library to handle most of the heavy lifting for us. In this article, we will cover a few popular form libraries in the React ecosystem:
- SurveyJS: A form-building library that allows developers to render JSON forms and surveys. Other than React, it includes integrations for Angular, Vue, jQuery, and Knockout
- React Hook Form: A headless library that allows developers to handle forms without writing too much boilerplate code. This library also supports React Native
- rc-field-form: Just like React Hook Form, rc-field-form lets users manage forms on both the web and mobile platforms. Moreover, it focuses on performance and efficiency. This is especially useful for developers who want to build lightweight apps
- Tanstack Form: A lightweight form management library built by theTanStack team. Furthermore, it supports numerous other libraries like Vue, Angular, Lit, and more
Now that we have briefly introduced some React form libraries, let’s explore them!
Setting up our React project
Before writing code, we first have to scaffold our React project. To do so, run the following command in the terminal:
#initialize React project with Typescript:npm create vite@latest form-libraries--template react-tscdform-librariesnpminstall#install the needed packages to run the project.
React form libraries: SurveyJS
As stated earlier, SurveyJS is a library geared towards building multi-page forms and surveys. It supports a variety of features, including:
- Localization: SurveyJS supports the automatic translation of strings, thus eliminating the need for manual input
- Visual form building: Enables users without coding expertise to create forms through a visual interface
- Customizable pre-styled components: Offers a range of pre-designed components that can be easily customized to match specific design needs
To include SurveyJS in our project, install it via npm:
npminstallsurvey-react-ui--save
This block of code showcases the SurveyJS library in action:
import"survey-core/defaultV2.min.css";import{Model,SurveyModel}from"survey-core";import{Survey}from"survey-react-ui";import{useCallback}from"react";exportfunctionSurveyExample(){//create our schema for our form:constsurveyJson={elements:[//configure our fields{name:"FirstName",title:"Enter your first name:",type:"text",},{name:"LastName",title:"Enter your last name:",type:"text",},],};//feed the schema into the modelconstsurvey=newModel(surveyJson);//handler function that runs when the user submits the formconstsurveyComplete=useCallback((survey:SurveyModel)=>{constuserOutput=survey.data;console.log(userOutput);},[]);//attach this handler to the formsurvey.onComplete.add(surveyComplete);return(<div>{/*Finally, pass our model and render the form*/}<Surveymodel={survey}/></div>);}//don't forget to render this component in App.tsx!
In the code snippet above:
- First, we declared the
surveyJson
variable, which will be the schema for our form. The schema will pass the data needed to render our form - Then, we initialized the
surveyComplete
handler. This function will run whenever the user submits the form. In this case, we are just logging out the user’s input to the console - Finally, we passed our model to the
Survey
component to render our form to the DOM
Let’s test it out! To run the project, type this command:
npm run dev
React Hook Form
React Hook Form is a dependency-free library that enables efficient form validation. It boasts the following features:
- Subscriptions: React Hook Form lets developers watch individual inputs without re-rendering parent components
- Re-render isolation: The library uses performance tricks to prevent unnecessary re-rendering in their app
- Headless: This means that developers have the freedom tochoose their favorite component libraries to use with React Hook Form
- Hook-based API: Allows components to access and manipulate local state with relative ease. This also indicates that the library follows React’s best practices
As always, the first step is to install React Hook Form in your project:
npminstallreact-hook-form
Here is a piece of code that demonstrates validation in React Hook Form:
import{useState}from"react";import{useForm,SubmitHandler}from"react-hook-form";typeInputs={twice:boolean;newjeans:boolean;name:string;};exportdefaultfunctionReactHookForm(){const{register,handleSubmit,watch,formState:{errors},}=useForm<Inputs>({defaultValues:{twice:true,name:"LogRocket"}});const[output,setOutput]=useState<Inputs>();constonSubmit:SubmitHandler<Inputs>=(data)=>setOutput(data);return(<div><h1>Yourfavoritegroup?</h1><formonSubmit={handleSubmit(onSubmit)}>{/* register your input into the hook by invoking the "register" function */}<label><inputtype="checkbox"{...register("twice")}/>Twice</label><label>{""}<inputtype="checkbox"{...register("newjeans")}/>NewJeans</label><label>{""}Name<inputtype="text"{...register("name")}/></label>{/* include validation with required or other standard HTML validation rules */}{/* errors will return when field validation fails */}<inputtype="submit"/></form><p>{output?.newjeans&&"newjeans was selected"}</p><p>{output?.twice&&"twice was selected"}</p><p>Name:{output?.name}</p></div>);}
Let’s break down this code piece by piece:
- First, we created an
Inputs
type, which contains the fields that we want to populate - Then, we used the
useForm
Hook and passed in our fields and default values via thedefaultValues
property - Afterwards, we declared our
onSubmit
handler, which will update a Hook calledoutput
. We will render theoutput
Hook to the DOM later in this code - Next, we used the
register
function on ourinput
components. This tells React that we want to connect our inputs with theuseForm
Hook - Finally, React will display the value of the
output
Hook depending on the user’s input
That’s it! Let’s test React Hook Form out:
rc-field-form
Similar to React Hook Form, rc-field-form is another React form library that focuses on performance and ease of use.
To get started, simply install the dependencies like so:
npminstallrc-field-form
This snippet shows how you can implement asynchronous validation on a text field via the rc-field-form library:
importForm,{Field}from"rc-field-form";constInput=({value="",...props})=><inputvalue={value}{...props}/>;exportconstRCFieldFormExample=()=>{return(<FormonFinish={(values)=>{console.log("Finish:",values);}}><Fieldname="username"validateTrigger={["onSubmit"]}rules={[{required:true},{validator(rule,value){if(value==="Log"){returnPromise.reject(alert("Not allowed!"));}returnPromise.resolve();},},]}><Inputplaceholder="Username"/></Field><Fieldname="password"><Inputplaceholder="Password"/></Field><button>Submit</button></Form>);};
Here’s a brief explanation of our program:
- We rendered the
Form
component and defined theonFinish
handler. This will tell React that it should output the user’s input to the console after submission - Then, we rendered two
Field
components: one forusername
and the other forpassword
- Then, for validation, we configured the
rules
prop in theusername
field. Here, we instructed the library that if theusername
field is set toLog
, it has to display an error message
Here’s the output of the code:
Nice! As you can see, our code works!
Tanstack forms with Zod
TheTanstack team needs no introduction. Recently, they introducedTanStack Form to their arsenal of high-quality utilities. Though still in beta, the library consists of an exhaustive list of features, including:
- Headless: Just like React Hook Form, TanStack Form handles all the logic and developers can use their component library of choice
- Asynchronous validation
- Lightweight
- Hook-based design
As always, the first step to use a library is to install it:
#react-form: to render and build forms#zod-form-adapter and zod: For validation purposes.npm i @tanstack/react-form @tanstack/zod-form-adapter zod
Next, let’s build a component that informs the user in case a validation error occurs:
importtype{FieldApi}from"@tanstack/react-form";functionFieldInfo({field}:{field:FieldApi<any,any,any,any>}){return(<>{/*If error occurs, display it. */}{field.state.meta.isTouched&&field.state.meta.errors.length?(<em>{field.state.meta.errors.join(",")}</em>):null}{field.state.meta.isValidating?"Validating...":null}</>);}
Here, we created a component calledFieldInfo
, which will check if the user has failed any validation checks. If this condition is met, it will display an error on the page.
Finally, write this block of code for form rendering and validation using Tanstack Form:
import{useForm}from"@tanstack/react-form";import{zodValidator}from"@tanstack/zod-form-adapter";import{z}from"zod";//step 1: define our schema and each field's requirementsconstuserSchema=z.object({//if the user's name is Log, display an error.firstName:z.string().refine((val)=>val!=="Log",{message:"[Form] First name cannot be Log!",}),//the user's age should be atleast 18.age:z.coerce.number().min(18,"Need to be an adult!"),});typeUser=z.infer<typeofuserSchema>;exportdefaultfunctionTanstackFormExample(){//use the useForm hook and define our default values.constform=useForm({defaultValues:{firstName:"",age:0,}asUser,onSubmit:async({value})=>{console.log(value);},//configure our validationvalidatorAdapter:zodValidator(),validators:{onSubmit:userSchema,},});return(<div><formonSubmit={(e)=>{e.preventDefault();e.stopPropagation();form.handleSubmit();}}><div>{/*Create our fields and inputs*/}<form.Fieldname="firstName"children={(field)=>{return(<><labelhtmlFor={field.name}>FirstName:</label><inputid={field.name}name={field.name}value={field.state.value}onBlur={field.handleBlur}onChange={(e)=>field.handleChange(e.target.value)}/><FieldInfofield={field}/></>);}}/></div><div>{/*Second input for the user's age*/}<form.Fieldname="age"children={(field)=>(<><labelhtmlFor={field.name}>Age:</label><inputid={field.name}name={field.name}value={field.state.value}onBlur={field.handleBlur}onChange={(e)=>field.handleChange(e.target.valueAsNumber)}/><FieldInfofield={field}/></>)}/></div><div></div>{/*This component will run when the form's state changes*/}<form.Subscribeselector={(state)=>{returnstate;}}children={(state)=>{return(//check if the user can submit the form:<buttontype="submit"disabled={!state.canSubmit}>{state.isSubmitting?"...":"Submit"}</button>);}}/></form></div>);}
This code might seem daunting at first, but most of it is boilerplate needed for the library to run. The explanation is in the code comments.
When run, the TanStack Form output should look like so:
Comparing the React form libraries we covered
Here is a table that compares the libraries we covered in this guide:
Library | Documentation | Community | Updates | Performance-focused | Notes |
---|---|---|---|---|---|
SurveyJS | Easy to follow and concise | Large and growing | Updates frequently | No | [Paid tier](https://surveyjs.io/pricing) for large projects, [part of a form library ecosystem](https://surveyjs.io/try/reactjs) |
React Hook Form | Easy to follow and concise | Extremely large and rapidly growing | Updates frequently | Yes | |
rc-field-form | A bit hard to follow. Not as easy as other libraries | Small but growing | Updates frequently | Yes | Built by the [Ant Design team](https://ant.design/), well-funded and unlikely to be abandoned. |
Tanstack Form | Easy to follow | Large and growing | Updates extremely frequently | Yes | Currently in beta, API breakages possible |
In this article, we learned about a few form-building libraries in React. Additionally, we also covered how we can perform rendering and validation on our forms in these libraries. In my hobby projects, I use React Hook Form because it offers a reliable and performant solution with a user-friendly developer experience.Here is the source code of the article.
Of course, depending on a project’s needs, users can also opt for libraries likeFormik orAnt Design for form management.
Thank you for reading!
Get set up with LogRocket's modern React error tracking in minutes:
- Visithttps://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side.
NPM:
$npm i--save logrocket // Code:import LogRocket from'logrocket'; LogRocket.init('app/id');
Script Tag:
AddtoyourHTML:<scriptsrc="https://cdn.lr-ingest.com/LogRocket.min.js"></script><script>window.LogRocket&&window.LogRocket.init('app/id');</script>
- (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
Top comments(1)

Really valued this summary of React libraries for building forms and surveys. Between performance analytics and useful application examples, you have found a decent mix. Particularly for those who prefer less re-renders and simpler code, React Hook Form's speed and simplicity definitely stand out. That said, it's fantastic to see Formik still being appreciated; many projects benefit from its developed ecology and simple design.
Survey JS also drew my eye. Its adaptability and methodical methodology provide fascinating opportunities beyond conventional shape construction based on data. This was a well-rounded analysis overall that provides careful comparisons to guide developers in making selections rather than only tool lists. A really useful article; thanks for distributing it. Explore our extensive range ofTopographical Survey by clicking this link to access our catalog, where you'll find detailed descriptions, pricing information, and customer reviews.
For further actions, you may consider blocking this person and/orreporting abuse