π₯ Stop Writing Boilerplate! How Formik + React Hooks Can Save You 500 Hours This Year π₯
Let's face it β form handling in React can be painful. As projects grow, developers often find themselves buried under piles of form validations, state management, and inconsistent user experiences.
You mightβve already heard of Formik β the popular form library for React. But what if I told you that most developers are underusing it? In this post, weβre going to dive into a powerful, lesser-known combination: Formik + Custom React Hooks.
We'll explore how this pairing can:
Ready to save weeks editing form logic in 2024? Let's get our hands dirty. π οΈ
A typical login form in plain React might look like this:
// LoginForm.jsx import { useState } from 'react'; function LoginForm() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); const handleSubmit = e => { e.preventDefault(); if (!email || !password) { setError('All fields are required.'); return; } // Call API or authenticate... }; return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={e => setEmail(e.target.value)} /> <input type="password" value={password} onChange={e => setPassword(e.target.value)} /> {error && <p>{error}</p>} <button type="submit">Login</button> </form> ); } export default LoginForm;
Not terrible, but this is just login. Doing even basic validation across five different forms? Youβre duplicating logic like a robot.
Formik simplifies form state and validation management. Pairing it with Yup, a JS schema validator, adds declarative, composable validation.
Letβs rewrite our login form the Formik way:
// LoginFormWithFormik.jsx import { Formik, Form, Field, ErrorMessage } from 'formik'; import * as Yup from 'yup'; const LoginSchema = Yup.object().shape({ email: Yup.string().email('Invalid email').required('Required'), password: Yup.string().min(6, 'Too short').required('Required'), }); function LoginForm() { const handleSubmit = (values) => { console.log('Submitted:', values); // Call API }; return ( <Formik initialValues={{ email: '', password: '' }} validationSchema={LoginSchema} onSubmit={handleSubmit} > <Form> <Field name="email" type="email" /> <ErrorMessage name="email" component="div" /> <Field name="password" type="password" /> <ErrorMessage name="password" component="div" /> <button type="submit">Login</button> </Form> </Formik> ); } export default LoginForm;
β
Zero manual useState management
β
Disables submit on validation errors
β
Clean, declarative code
What if you need to reuse business logic across forms? Create a custom hook to encapsulate logic!
// hooks/useLoginForm.js import * as Yup from 'yup'; export const useLoginForm = () => { const initialValues = { email: '', password: '' }; const validationSchema = Yup.object({ email: Yup.string().email('Bad email').required('Required'), password: Yup.string().min(6, 'Minimum 6 characters').required('Required'), }); const onSubmit = (values, { setSubmitting }) => { console.log('Login:', values); // ...API call setSubmitting(false); }; return { initialValues, validationSchema, onSubmit }; };
Now update your form to use this hook:
import { Formik, Form, Field, ErrorMessage } from 'formik'; import { useLoginForm } from './hooks/useLoginForm'; function LoginForm() { const form = useLoginForm(); return ( <Formik {...form}> <Form> <Field name="email" type="email" /> <ErrorMessage name="email" component="div" /> <Field name="password" type="password" /> <ErrorMessage name="password" component="div" /> <button type="submit">Login</button> </Form> </Formik> ); }
You could easily turn useLoginForm into useFormBuilder(type) and build a dynamic, unified form system.
Formik also lets you access field state via hooks:
import { useField } from 'formik'; function FancyEmailInput() { const [field, meta] = useField('email'); return ( <div> <input {...field} type="email" placeholder="What's your email?" /> {meta.touched && meta.error && ( <span className="error">{meta.error}</span> )} </div> ); }
Use this pattern to build entire design systems that interface seamlessly with Formik.
Few things can instantly 10x DX (Developer Experience) like having:
In teams, this pays off instantly by reducing onboarding time, PR reviews, and logic bugs inside forms.
Hereβs what we covered:
β
Plain Form β Boilerplate
β
Formik + Yup β Cleaner, validatable code
β
Custom Hooks + Formik β Scalable, reusable logic
β
useField β Power up custom components
<pre>{JSON.stringify(values, null, 2)}</pre> <pre>{JSON.stringify(errors, null, 2)}</pre>
Add them below forms in dev mode for ultra-fast debugging.
Forms donβt have to be painful. With the Formik + React Hooks combo, you'll write less code, have fewer bugs, and stop pulling your hair out.
Start using these patterns today and you just might earn back ~500 hours this year β or at least your front-end sanity π.
π¬ Have a juicy form horror story? Share it in the comments below!
π οΈ Tags: react, formik, web-development, productivity
β¨ If you need this done β we offer frontend development services!
Information