Crafting Dynamic Forms in React with Form Atoms: A Comprehensive Guide

Pawan GangwaniPawan Gangwani
4 min read

Introduction

In this guide, we’ll explore how to create forms using the form-atoms library. We’ll start with simple forms and gradually move to more complex forms, including lists. This guide will cover the following:

  1. Setting up the environment

  2. Creating a simple form

  3. Adding validation

  4. Creating a list form

  5. Advanced form with nested lists

1. Setting Up the Environment

First, let’s set up our project. Ensure you have Node.js installed, then create a new project and install the necessary dependencies.

npx create-react-app form-atoms-demo
cd form-atoms-demo
npm install jotai form-atoms @form-atoms/field @form-atoms/list-atom zod

2. Creating a Simple Form

We’ll start by creating a simple form with text and number fields.

Step 1: Define the Form Fields

Create a new file PersonForm.js and define the form fields using @form-atoms/field.

import { textField, numberField } from "@form-atoms/field";
import { formAtom, useForm, InputField } from "form-atoms";

const personForm = formAtom({
  name: textField(),
  age: numberField(),
});

export const PersonForm = () => {
  const { fieldAtoms, submit } = useForm(personForm);

  return (
    <form onSubmit={submit(console.log)}>
      <InputField atom={fieldAtoms.name} label="Your Name" />
      <InputField atom={fieldAtoms.age} label="Your Age" />
      <button type="submit">Submit</button>
    </form>
  );
};

Step 2: Use the Form in Your App

Import and use the PersonForm component in your App.js.

import React from "react";
import { PersonForm } from "./PersonForm";

function App() {
  return (
    <div className="App">
      <h1>Simple Form</h1>
      <PersonForm />
    </div>
  );
}

export default App;

3. Adding Validation

To add validation, we use the zod schema. Let’s add some basic validations to our form fields.

Step 1: Update the Form Fields

Update the PersonForm.js to include validations.

import { z } from "zod";

const personForm = formAtom({
  name: textField({ schema: (s) => s.min(1, "Name is required") }),
  age: numberField({ schema: (s) => s.min(18, "Must be at least 18") }),
});

Step 2: Display Validation Errors

Update the PersonForm component to display validation errors.

export const PersonForm = () => {
  const { fieldAtoms, submit, errors } = useForm(personForm);

  return (
    <form onSubmit={submit(console.log)}>
      <InputField atom={fieldAtoms.name} label="Your Name" />
      {errors.name && <span>{errors.name}</span>}
      <InputField atom={fieldAtoms.age} label="Your Age" />
      {errors.age && <span>{errors.age}</span>}
      <button type="submit">Submit</button>
    </form>
  );
};

4. Creating a List Form

Now, let’s create a more complex form that includes a list of items.

Step 1: Define the List Fields

Create a new file EnvironmentForm.js and define the list fields using @form-atoms/list-atom.

import { fieldAtom, formAtom, useForm, InputField } from "form-atoms";
import { listAtom, List } from "@form-atoms/list-atom";

const environmentVariables = listAtom({
  name: "environment",
  value: [{ key: "GITHUB_SECRET", value: "<hash>" }],
  fields: ({ key, value }) => ({
    key: fieldAtom({ value: key }),
    value: fieldAtom({ value }),
  }),
});

const form = formAtom({ environmentVariables });

export const EnvironmentForm = () => {
  const { submit } = useForm(form);

  return (
    <form onSubmit={submit(console.log)}>
      <List atom={environmentVariables}>
        {({ fields }) => (
          <>
            <InputField atom={fields.key} label="Variable Key" />
            <InputField atom={fields.value} label="Variable Value" />
          </>
        )}
      </List>
      <button type="submit">Submit</button>
    </form>
  );
};

Step 2: Use the List Form in Your App

Import and use the EnvironmentForm component in your App.js.

import React from "react";
import { EnvironmentForm } from "./EnvironmentForm";

function App() {
  return (
    <div className="App">
      <h1>Environment Variables Form</h1>
      <EnvironmentForm />
    </div>
  );
}

export default App;

5. Advanced Form with Nested Lists

Finally, let’s create an advanced form with nested lists.

Step 1: Define the Nested List Fields

Create a new file ProjectForm.js and define the nested list fields.

import { fieldAtom, formAtom, useForm, InputField } from "form-atoms";
import { listAtom, List } from "@form-atoms/list-atom";

const projectForm = formAtom({
  projectName: fieldAtom(),
  teamMembers: listAtom({
    name: "teamMembers",
    value: [{ name: "Alice", tasks: [{ title: "Task 1" }] }],
    fields: ({ name, tasks }) => ({
      name: fieldAtom({ value: name }),
      tasks: listAtom({
        name: "tasks",
        value: tasks,
        fields: ({ title }) => ({
          title: fieldAtom({ value: title }),
        }),
      }),
    }),
  }),
});

export const ProjectForm = () => {
  const { submit } = useForm(projectForm);

  return (
    <form onSubmit={submit(console.log)}>
      <InputField atom={projectForm.projectName} label="Project Name" />
      <List atom={projectForm.teamMembers}>
        {({ fields }) => (
          <>
            <InputField atom={fields.name} label="Team Member Name" />
            <List atom={fields.tasks}>
              {({ fields }) => (
                <InputField atom={fields.title} label="Task Title" />
              )}
            </List>
          </>
        )}
      </List>
      <button type="submit">Submit</button>
    </form>
  );
};

Step 2: Use the Nested List Form in Your App

Import and use the ProjectForm component in your App.js.

import React from "react";
import { ProjectForm } from "./ProjectForm";

function App() {
  return (
    <div className="App">
      <h1>Project Form</h1>
      <ProjectForm />
    </div>
  );
}

export default App;

Conclusion

In this guide, we’ve covered the basics of creating forms using form-atoms. We started with a simple form, added validation, created a list form, and finally built an advanced form with nested lists. The form-atoms library provides a flexible and powerful way to manage form state in React applications.

Feel free to explore more features and customize your forms as needed. Happy coding!


6
Subscribe to my newsletter

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

Written by

Pawan Gangwani
Pawan Gangwani

I’m Pawan Gangwani, a passionate Full Stack Developer with over 12 years of experience in web development. Currently serving as a Lead Software Engineer at Lowes India, I specialize in modern web applications, particularly in React and performance optimization. I’m dedicated to best practices in coding, testing, and Agile methodologies. Outside of work, I enjoy table tennis, exploring new cuisines, and spending quality time with my family.