Frontend Form Management - department-of-veterans-affairs/caseflow GitHub Wiki

Form Management & Validation

Caseflow is an application built around forms. From intake to scheduling of hearings, nearly every part of Caseflow depends on the use of forms. As such, we try to make using them as easy as possible!

React Hook Form

Instead of writing bespoke logic for managing forms and/or form fields for every use case, we can take advantage of libraries that can handle much of the boilerplate functionality for us. We have adopted the usage of React Hook Form as a form management library. It allows us to rapidly build forms and not have to worry about getting/setting all the individual field values, building out our own custom validation, and more — all using a lightweight standards-based implementation.

By passing register into the inputRef prop on our form fields, we allow the usage of uncontrolled components (eliminating the need to set value and onChange on each field), but still maintain the overall form state. We pass handleSubmit (returned from useForm) to the onSubmit prop of the form, allowing it to intercept the submission and perform validation, etc before passing the full data to our specified callback function.

By default, useForm runs validation, etc on form submission. However, it supports specifying these modes: onSubmit, onBlur, onChange, onTouched, or all

Basic Usage

import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import TextField from '../../components/TextField';
import Button from '../../components/Button';

export const MyComponent = () => {
    const { register, handleSubmit } = useForm();

    const onSubmit = ({veteranName}) => {
        // If we've gottten to this point, the form is valid and has been submitted.
        // This callback could be defined in your component, passed in props, etc

        // The argument is an object with keys of the various field names
    }

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <TextareaField
            inputRef={register}
            name="veteranName"
            label="Veteran Name"
            strongLabel
            />

            <Button type="submit">Submit</Button>
        </form>
    )
}

Validation with Yup

Using the form management library becomes particularly useful when coupled with a validation schema. Yup is a library that allows us to build validation schemata, and it integrates really easily with react-hook-form.

Note that validation for React Hook forms is async and expectations during testing need to be wrapped in a waitFor (example)

Basic Integration of React Hook Form & Yup

import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers';
import * as yup from 'yup';

import TextField from '../../components/TextField';
import Button from '../../components/Button';

const TIMELY_OPTIONS = [
  { displayText: 'Yes', value: 'yes' },
  { displayText: 'No', value: 'no' },
];

const schema = yup.object().shape({
  veteranName: yup.string().required(),
  timely: yup.string().oneOf(['yes', 'no']),
});

export const MyComponent = () => {
    const { register, handleSubmit, formState, errors } = useForm({
        resolver: yupResolver(schema),
        mode: 'onChange',
    });

    const onSubmit = (formData) => console.log('success!', formData);

    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <TextareaField
            inputRef={register}
            name="veteranName"
            label="Veteran Name"
            strongLabel
            />

            <RadioField
            name="timely"
            label="Is this request timely?"
            options={TIMELY_OPTIONS}
            inputRef={register}
            strongLabel
            vertical
            />

            <Button type="submit" disabled={!formState.isValid}>Submit</Button>
        </form>
    )
}

Examples

You can see these patterns utilized in the RecommendDocketSwitchForm component

⚠️ **GitHub.com Fallback** ⚠️