Written by: Geoffrey Callaghan

Final Form Tutorial

Final Form Tutorial

Final Form is a framework-agnostic form state management library that provides powerful tools for building and managing forms in React. This tutorial will guide you through the basics of setting up and using Final Form with React.

Step 1: Setup Your React Project

If you don’t have a React project set up, create one using Create React App:

npx create-react-app my-final-form-app
cd my-final-form-app

Step 2: Install Final Form and React Final Form

Install both final-form and react-final-form packages:

npm install final-form react-final-form
# or
yarn add final-form react-final-form

Step 3: Basic Usage

Here’s how to create a simple form using Final Form and React Final Form.

  1. Import Final Form Components:
import React from 'react';
import { Form, Field } from 'react-final-form';
  1. Create a Basic Form Component:
const MyForm = () => {
  const onSubmit = async (values) => {
    window.alert(JSON.stringify(values, 0, 2));
  };

  return (
    <Form
      onSubmit={onSubmit}
      render={({ handleSubmit, form, submitting, pristine, values }) => (
        <form onSubmit={handleSubmit}>
          <div>
            <label>Name</label>
            <Field name="name" component="input" placeholder="Name" />
          </div>
          <div>
            <label>Email</label>
            <Field name="email" component="input" type="email" placeholder="Email" />
          </div>
          <div>
            <button type="submit" disabled={submitting || pristine}>
              Submit
            </button>
            <button
              type="button"
              onClick={form.reset}
              disabled={submitting || pristine}
            >
              Reset
            </button>
          </div>
          <pre>{JSON.stringify(values, 0, 2)}</pre>
        </form>
      )}
    />
  );
};

export default MyForm;

Step 4: Validating Form Fields

You can add validation to your form fields by providing a validate function to the Form component.

  1. Validation Function:
const validate = values => {
  const errors = {};
  if (!values.name) {
    errors.name = 'Required';
  }
  if (!values.email) {
    errors.email = 'Required';
  } else if (!/\S+@\S+\.\S+/.test(values.email)) {
    errors.email = 'Invalid email address';
  }
  return errors;
};
  1. Using the Validation Function:
<Form
  onSubmit={onSubmit}
  validate={validate}
  render={({ handleSubmit, form, submitting, pristine, values, errors }) => (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Name</label>
        <Field name="name" component="input" placeholder="Name" />
        {errors.name && <span>{errors.name}</span>}
      </div>
      <div>
        <label>Email</label>
        <Field name="email" component="input" type="email" placeholder="Email" />
        {errors.email && <span>{errors.email}</span>}
      </div>
      <div>
        <button type="submit" disabled={submitting || pristine}>
          Submit
        </button>
        <button
          type="button"
          onClick={form.reset}
          disabled={submitting || pristine}
        >
          Reset
        </button>
      </div>
      <pre>{JSON.stringify(values, 0, 2)}</pre>
    </form>
  )}
/>

Step 5: Custom Field Components

You can create custom field components to encapsulate field rendering logic.

  1. Custom Input Component:
const MyInput = ({ input, meta, ...rest }) => (
  <div>
    <input {...input} {...rest} />
    {meta.error && meta.touched && <span>{meta.error}</span>}
  </div>
);
  1. Using the Custom Input Component:
<Field name="name" component={MyInput} placeholder="Name" />
<Field name="email" component={MyInput} type="email" placeholder="Email" />

Step 6: Handling Form Submission

You can handle form submission using the onSubmit prop of the Form component.

  1. Handle Form Submission:
const onSubmit = async (values) => {
  // perform any submission logic here
  console.log('Form values:', values);
};

Step 7: Advanced Usage

Final Form offers many advanced features such as field-level validation, array fields, and more.

  1. Field-Level Validation:
const validateName = value => (value ? undefined : 'Required');

<Field name="name" component="input" placeholder="Name" validate={validateName} />
  1. Array Fields:

To handle array fields, you can use FieldArray from react-final-form-arrays.

npm install react-final-form-arrays
import { FieldArray } from 'react-final-form-arrays';

const MyForm = () => (
  <Form
    onSubmit={onSubmit}
    render={({ handleSubmit }) => (
      <form onSubmit={handleSubmit}>
        <FieldArray name="friends">
          {({ fields }) => (
            <div>
              {fields.map((name, index) => (
                <div key={name}>
                  <Field name={`${name}.firstName`} component="input" placeholder="First Name" />
                  <Field name={`${name}.lastName`} component="input" placeholder="Last Name" />
                  <button type="button" onClick={() => fields.remove(index)}>
                    Remove
                  </button>
                </div>
              ))}
              <button type="button" onClick={() => fields.push({})}>
                Add Friend
              </button>
            </div>
          )}
        </FieldArray>
        <button type="submit">Submit</button>
      </form>
    )}
  />
);

Conclusion

Final Form is a powerful and flexible library for managing form state in React applications. This tutorial covered the basics of setting up and using Final Form, including creating forms, adding validation, and handling form submission. For more advanced usage and detailed documentation, refer to the official Final Form documentation.