Written by: ekwoster.dev on Fri Aug 29

πŸ”₯ Stop Writing Boilerplate! How Formik + React Hooks Can Save You 500 Hours This Year πŸ”₯

πŸ”₯ Stop Writing Boilerplate! How Formik + React Hooks Can Save You 500 Hours This Year πŸ”₯

Cover image for πŸ”₯ Stop Writing Boilerplate! How Formik + React Hooks Can Save You 500 Hours This Year πŸ”₯

πŸ”₯ Stop Writing Boilerplate! How Formik + React Hooks Can Save You 500 Hours This Year πŸ”₯

Introduction

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:

  • Eliminate repetitive form boilerplate code 🎯
  • Make your form components cleaner and more maintainable πŸ’…
  • Improve validation UX without breaking your brain 🧠

Ready to save weeks editing form logic in 2024? Let's get our hands dirty. πŸ› οΈ


πŸ’£ The Pain: Forms Before Formik (and Why Hooks Alone Aren’t Enough)

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.


πŸš€ Enter Formik + Yup: The Validation Dream Team

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


🧠 Superpower Combo: Custom Hooks + Formik Context

What if you need to reuse business logic across forms? Create a custom hook to encapsulate logic!

Let’s Make a useLoginForm Hook

// 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>
  );
}

🧼 Clean, don’t repeat yourself (DRY), fully reusable.

You could easily turn useLoginForm into useFormBuilder(type) and build a dynamic, unified form system.


πŸ‘€ Bonus: Real-Time UX Improvements with useField Hook

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.


✨ Takeaways: Use these patterns today

Few things can instantly 10x DX (Developer Experience) like having:

  • A consistent form logic template via custom hooks
  • Declarative validation that’s testable
  • Components that separate UX and logic cleanly

In teams, this pays off instantly by reducing onboarding time, PR reviews, and logic bugs inside forms.


πŸ§ͺ TLDR – Code Snippets Crash Course

Here’s what we covered:

βœ… Plain Form β†’ Boilerplate
βœ… Formik + Yup β†’ Cleaner, validatable code
βœ… Custom Hooks + Formik β†’ Scalable, reusable logic
βœ… useField β†’ Power up custom components


πŸ’‘ Pro Tip: Add Formik Debug Tools

<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.


🧭 Where to Learn More


πŸ‘‹ Final Word

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!