π₯ Stop Using Forms Like It's 2015: Master Complex Forms in React with Formik + Yup + Dynamic Fields π₯
If you've ever built a form in React, chances are you've ended up tangled in useState() hooks, onChange handlers, and spaghetti validation logic that makes your app feel more like a bomb squad operation than front-end development.
β Let's face it: Forms in React suck... unless you're using the right tools.
Say hello to your new best friends:
In this blog post, you're going to level-up from basic form handling to building complex, conditional, dynamic, and validated forms like a true pro.
First, install the necessary packages:
npm install formik yup
import React from 'react'; import { Formik, Form, Field, ErrorMessage } from 'formik'; import * as Yup from 'yup'; const SignupSchema = Yup.object().shape({ name: Yup.string().required('Required'), email: Yup.string().email('Invalid email').required('Required'), password: Yup.string().min(6, 'Too Short!').required('Required') }); const SimpleForm = () => ( <div> <h1>Signup</h1> <Formik initialValues={{ name: '', email: '', password: '' }} validationSchema={SignupSchema} onSubmit={values => { console.log(values); }} > {() => ( <Form> <label>Name</label> <Field name="name" /> <ErrorMessage name="name" component="div" /> <label>Email</label> <Field name="email" type="email" /> <ErrorMessage name="email" component="div" /> <label>Password</label> <Field name="password" type="password" /> <ErrorMessage name="password" component="div" /> <button type="submit">Submit</button> </Form> )} </Formik> </div> ); export default SimpleForm;
Letβs say you want users to input multiple hobbies, dynamically adding fields. You donβt want to guess how many fields they need, right? You want something smart.
Enter FieldArray βΉοΈββοΈ
import { FieldArray } from 'formik'; const DynamicForm = () => ( <Formik initialValues={{ hobbies: [''] }} onSubmit={values => { console.log(values); }} > {({ values }) => ( <Form> <h1>Enter Hobbies</h1> <FieldArray name="hobbies"> {({ push, remove }) => ( <div> {values.hobbies.map((_, index) => ( <div key={index}> <Field name={`hobbies.${index}`} /> <button type="button" onClick={() => remove(index)}> Remove </button> </div> ))} <button type="button" onClick={() => push('')}> Add Hobby </button> </div> )} </FieldArray> <button type="submit">Submit</button> </Form> )} </Formik> );
Serious forms require conditional logic. For example, if a user selects "Employed", show employer-related fields.
const ConditionalForm = () => ( <Formik initialValues={{ status: '', company: '' }} validationSchema={Yup.object({ status: Yup.string().required(), company: Yup.string().when('status', { is: 'employed', then: Yup.string().required('Company name is required') }) })} onSubmit={values => console.log(values)} > {({ values }) => ( <Form> <label>Status</label> <Field as="select" name="status"> <option value="">Select</option> <option value="student">Student</option> <option value="employed">Employed</option> </Field> <ErrorMessage name="status" component="div" /> {values.status === 'employed' && ( <> <label>Company</label> <Field name="company" /> <ErrorMessage name="company" component="div" /> </> )} <button type="submit">Submit</button> </Form> )} </Formik> );
β Now youβve got schema-based validation AND dynamic fields β like a boss.
Donβt repeat yourself. Abstract form inputs like this:
const MyTextInput = ({ label, ...props }) => ( <div> <label>{label}</label> <Field {...props} /> <ErrorMessage name={props.name} component="div" /> </div> ); // Use it like: <MyTextInput label="Name" name="name" type="text" />
Formik forms return predictable props that are very testable using Testing Library:
import { render, screen, fireEvent } from '@testing-library/react'; import SimpleForm from './SimpleForm'; test('form submits correct data', () => { render(<SimpleForm />); fireEvent.change(screen.getByLabelText(/name/i), { target: { value: 'Alice' } }); fireEvent.change(screen.getByLabelText(/email/i), { target: { value: '[email protected]' } }); fireEvent.change(screen.getByLabelText(/password/i), { target: { value: '123456' } }); fireEvent.click(screen.getByText(/submit/i)); // Add your expectations or mock submit handler here });
Formik + Yup isnβt just a pairing, itβs a superpower combo for form management in React. Youβve seen how to:
Youβre now ready to build enterprise-grade forms without losing hair. π§ββοΈβ¨
Want to go further? Try integrating:
Or... try building a form builder using Formik + JSON schemas π€―
Start building forms that work for users β not against them.
π‘ If you need help building dynamic, interactive frontends like this - we offer frontend development services.
Information