Formik: The Checkbox Form Journey – What Should Neo Choose?

Prateek TewariPrateek Tewari
7 min read

It’s Saturday morning, and Neo finds himself staring at his computer screen, ready to dive into the world of Formik. Neo’s mission for the weekend is simple but daunting: explore Formik and integrate it into his everyday work.

Enter Mobius, Neo’s mentor and guide. Imagine the iconic red and blue pill scene from The Matrix, but instead of deciding between waking up to reality or staying blissfully ignorant, Neo must choose between two programming approaches.

Mobius, dressed in his usual calm demeanor, stands beside Neo.

"Neo, you're at a crossroads," Mobius says. "In your left hand, you have the traditional way of building forms in React—painstaking, verbose, and prone to bugs. But in your right hand, you have Formik—a form management library that will make your life easier. The choice is yours."

Neo looks down at his hands—imaginary pills representing two coding paths—and then back at the screen where his React app awaits.

"I think I’m ready for Formik," Neo says confidently, choosing the metaphorical red pill.

"Excellent," Mobius smiles, "Let's begin."


Setting the Scene: Introducing Formik

As Neo takes the plunge, Mobius explains: "Formik is all about making form state management in React a breeze. No more manual tracking of input values or worrying about form submissions—Formik handles it for you."

Mobius snaps his fingers, and a block of code appears on Neo’s screen:

import { Formik, Field, Form } from 'formik';
import * as Yup from 'yup';

"Here we’re importing Formik, Field, and Form from the library. These are our key players," Mobius explains. "Formik wraps your entire form, Field represents each individual input, and Form is just like a regular HTML form tag but powered by Formik."

Neo nods, starting to feel the power of Formik coursing through his code.


The Checkbox Matrix

"Now," Mobius continues, "imagine you need a form with multiple checkboxes. This is where things can get tricky—managing all those checkbox states manually? Ugh. But with Formik, it’s as smooth as choosing the red pill."

He gestures, and more code appears:

const mockFetchCheckboxData = (): Promise<CheckboxData[]> => {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve([
                { category: 'Category 1', items: [{ label: 'Option 1', value: 'option1' }, { label: 'Option 2', value: 'option2' }] },
                { category: 'Category 2', items: [{ label: 'Option 3', value: 'option3' }, { label: 'Option 4', value: 'option4' }] },
            ]);
        }, 1000);
    });
};

"Here, we're simulating a fetch call to get checkbox data, grouped by category. Each category contains a set of checkbox options."

"Cool," Neo says, "But how does Formik know what to do with all that data?"

"Patience, Neo. Watch closely."


Handling Form State with Grace

Mobius moves swiftly, typing the next piece of the puzzle:

const initialValues = checkboxData.reduce((acc, category) => {
    category.items.forEach((item) => {
        acc[item.value] = false;
    });
    return acc;
}, {});

"Formik needs an initialValues object," Mobius explains, "which sets each checkbox’s initial state to false. This function dynamically creates that object based on the checkbox data we fetched."

"So I don’t need to manually define every checkbox state?" Neo asks, eyebrows raised.

"Exactly," Mobius replies. "Formik handles it. Once the data is in place, Formik takes over."


Rendering the Checkbox Form

The screen lights up with more code:

<Formik
    initialValues={initialValues}
    onSubmit={(values) => {
        alert(JSON.stringify(values, null, 2));
    }}
>
    {({ setFieldValue }) => (
        <Form>
            <h2>Checkbox Form</h2>
            {checkboxData.map((category) => (
                <div key={category.category}>
                    <h3>{category.category}</h3>
                    {category.items.map((item) => (
                        <label key={item.value}>
                            <Field type="checkbox" name={item.value} /> {item.label}
                        </label>
                    ))}
                </div>
            ))}
            <button type="submit">Submit</button>
        </Form>
    )}
</Formik>

"That’s a lot," Neo says, squinting at the screen.

"Let me break it down," Mobius replies, leaning in. "We pass initialValues and an onSubmit function to Formik. The form renders checkboxes grouped by category, and when you click 'Submit', Formik handles all the form state and passes the values back to you."


The Magic of setFieldValue

"But wait," Neo interjects, "How can I select all the checkboxes at once? I’ve got categories here, and manually clicking each checkbox seems inefficient."

"Ah," Mobius smiles knowingly, "Let me show you the magic of setFieldValue."

With a flick of his wrist, Mobius adds a feature to the form:

const handleSelectAll = (setFieldValue) => {
    checkboxData.forEach((category) => {
        category.items.forEach((item) => {
            setFieldValue(item.value, true);
        });
    });
};

"And here," Mobius says, pointing to a line of code, "you can call this function whenever you need to select all checkboxes at once. It updates the form state for you instantly."

Neo’s eyes widen. "That’s incredible. I don’t need to manually manage any of this?"

"Precisely," Mobius replies. "Formik lets you focus on what matters—building features—without worrying about tedious state management."


Final Thoughts: Neo’s Formik Awakening

Neo sits back in his chair, impressed with how effortlessly Formik handled what would otherwise be complex form logic.

"So," Mobius asks, "Was the journey worth it?"

"Absolutely," Neo replies, a sense of confidence growing inside him. "With Formik, I don’t have to worry about managing input state, validation, or form submission logic. I can just focus on building."

Mobius smiles. "Welcome to the world of Formik, Neo. Remember, with great power comes… well, easier forms."

As Neo watches the screen, his code comes to life—a sleek form with dynamically fetched checkboxes, ready to be submitted at the click of a button.

import React, { useEffect, useState } from 'react';
import { Formik, Field, Form } from 'formik';
import * as Yup from 'yup';

interface CheckboxData {
  category: string;
  items: { label: string; value: string }[];
}

const mockFetchCheckboxData = (): Promise<CheckboxData[]> => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve([
        { category: 'Category 1', items: [{ label: 'Option 1', value: 'option1' }, { label: 'Option 2', value: 'option2' }, { label: 'Option 3', value: 'option3' }, { label: 'Option 4', value: 'option4' }] },
        { category: 'Category 2', items: [{ label: 'Option 5', value: 'option5' }, { label: 'Option 6', value: 'option6' }, { label: 'Option 7', value: 'option7' }, { label: 'Option 8', value: 'option8' }] },
        { category: 'Category 3', items: [{ label: 'Option 9', value: 'option9' }, { label: 'Option 10', value: 'option10' }, { label: 'Option 11', value: 'option11' }, { label: 'Option 12', value: 'option12' }] },
        { category: 'Category 4', items: [{ label: 'Option 13', value: 'option13' }, { label: 'Option 14', value: 'option14' }, { label: 'Option 15', value: 'option15' }, { label: 'Option 16', value: 'option16' }] },
      ]);
    }, 1000);
  });
};

const formStyle: React.CSSProperties = {
  maxWidth: '600px',
  margin: '50px auto',
  padding: '20px',
  border: '1px solid #ccc',
  borderRadius: '10px',
  backgroundColor: '#f9f9f9',
  textAlign: 'center',
};

const dividerStyle: React.CSSProperties = {
  height: '1px',
  backgroundColor: '#ddd',
  margin: '20px 0',
};

const linkStyle: React.CSSProperties = {
  color: '#007bff',
  textDecoration: 'none',
  cursor: 'pointer',
};

const checkboxStyle: React.CSSProperties = {
  margin: '10px 0',
};

const MyFormWithCheckboxes = () => {
  const [checkboxData, setCheckboxData] = useState<CheckboxData[]>([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    mockFetchCheckboxData().then((data) => {
      setCheckboxData(data);
      setIsLoading(false);
    });
  }, []);

  const initialValues = checkboxData.reduce((acc, category) => {
    category.items.forEach((item) => {
      acc[item.value] = false;
    });
    return acc;
  }, {} as { [key: string]: boolean });

  const handleSelectAll = (setFieldValue: any) => {
    checkboxData.forEach((category) => {
      category.items.forEach((item) => {
        setFieldValue(item.value, true);
      });
    });
  };

  return isLoading ? (
    <div>Loading...</div>
  ) : (
    <Formik
      initialValues={initialValues}
      validationSchema={Yup.object({})} // No specific validation, just tracking checkbox state
      onSubmit={(values) => {
        alert(JSON.stringify(values, null, 2));
      }}
    >
      {({ setFieldValue }) => (
        <Form style={formStyle}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <h2>Checkbox Form</h2>
            <span style={linkStyle} onClick={() => handleSelectAll(setFieldValue)}>
              Select all checkboxes
            </span>
          </div>

          <div style={dividerStyle}></div>

          {/* Loop through categories */}
          {checkboxData.map((category) => (
            <div key={category.category}>
              <h3>{category.category}</h3>
              {category.items.map((item) => (
                <div key={item.value} style={checkboxStyle}>
                  <label>
                    <Field type="checkbox" name={item.value} /> {item.label}
                  </label>
                </div>
              ))}
              <div style={dividerStyle}></div>
            </div>
          ))}

          <button type="submit" style={{ cursor: 'pointer', padding: '10px', backgroundColor: '#4CAF50', color: '#fff', border: 'none', borderRadius: '5px' }}>
            Submit
          </button>
        </Form>
      )}
    </Formik>
  );
};

export default MyFormWithCheckboxes;

Closing Words

For anyone like Neo, starting their journey with Formik might feel like choosing between the red and blue pill. But once you step into the world of Formik, you’ll wonder how you ever managed without it.

This weekend project just got a whole lot easier, thanks to Formik. So, are you ready to take the red pill and simplify your React forms?


Key Takeaways:

  • Formik simplifies form state management, making it easier to handle even complex forms.

  • Dynamic Forms: Fetch data for checkboxes or any form elements dynamically.

  • Initial Values: Auto-generate initial form values based on data.

  • Form Submission: Formik handles the submission logic, passing all form values with minimal effort.

Happy coding!


Now, Neo's journey with Formik has just begun. What about yours?

13
Subscribe to my newsletter

Read articles from Prateek Tewari directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Prateek Tewari
Prateek Tewari