React Form Validation with Informed
Tags: form, validation
Published: 2022-11-08 17:04:17

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/formvalidation_271bb5960fa36ecd5e9551975c6664f1.jpg" alt="Stylized image of several forms."/></figure>

Form validation is an effective way to control the type of values that are provided in the proper format, preventing security vulnerabilities, malicious users, and entering incorrect data. It guarantees the data submitted matches the requirement. There are many validation frameworks/libraries that are used to handle [React form validation](https://code.pieces.app/blog/react-form-validation-with-yup-and-formik) in web applications; Informed is one such tool.

## What is Informed?

[Informed](https://www.npmjs.com/package/informed) is a React form validation tool used to create robust forms. It’s a simple framework that enables you to add custom inputs, dynamic forms, and multi-step forms to your application while making it simple to specify input error messages. It resolves the hassle of handling form state.

### Getting Started With Informed

This section will walk you through integrating the Informed React validation library into your application, along with validating fields and creating custom inputs. In addition, we'll create a React application and install the Informed library by performing either of the following commands:

```
yarn add informed
```

or

```
npm install informed
```

After installing the library, we’ll modify our `App.css` file by pasting the code block below:

```
* {
overflow-x: hidden;
}

.App {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background-color: #fff;
  color: #000;
  min-height: 100vh;
  width: 100vw;
  padding: 20px;
}

form {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: flex-start;
  width: 700px;
  padding: 15px;
  box-shadow: 10px 10px 15px lightblue;
  border: 1px solid #eee;
  border-radius: 2px;
}

div {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 5px;
}

input {
  width: -webkit-fill-available;
  padding: 5px 10px;
  margin: 5px 0;
}

button {
  border: none;
  margin-top: 10px;
  padding: 10px 25px;
  border-radius: 5px;
  color: #fff;
  background-color: #000;
  cursor: pointer;
}

span {
  color: #ff0000;
}
```

## React Form Validation with Informed

In this section, we’ll go over how to include Informed in your application. By default, the Informed library features native DOM input elements that are controlled by the React form library. This makes it easy to retrieve and manipulate form values; it handles everything related to the form state. Using the code block below, we’ll alter the `App.js` component:

```
import { Form, Input, Debug } from 'informed';
import './App.css';


const App = () => (
 <div className="App">
     <Form>
      <div>
       <Input className="input" name="name" label="Name" placeholder="Elon" />
       <Input
        className="input"
        name="age"
        type="number"
        label="Age"
       />
       <Input
        className="input"
        name="phone"
        label="Phone"
        formatter="+234 (###)-###-####"
       />
      <button type="submit">Submit</button>
     </div>
     <Debug/>
    </Form>
  </div>
);

export default App;
```

The code block above demonstrates how components imported from the Informed library are simply implemented. It’s critical to note the Debug component; this component displays the whole state of your form in real time, allowing for easier debugging. Also, the formatter prop shows you how to format input values. This can be added to text inputs as well.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image_fdf21850d5a9bf3250c13a44f7c4ef88.png" alt="An example of React form validation."/><figcaption>Basic Informed</figcaption></figure>

### Validation Hooks

The Informed library has a variety of hooks that help with various parts of managing simple to complex React forms in your application. We'll be looking at it in this section:

#### useFormState

The `useFormState` hook from the Informed library gives you access to the form state properties:

```
import { Form, Input, useFormState } from 'informed';

const ComponentUsingFormState = () => {
 const formState = useFormState();
 return (
  <pre>
   <code>{JSON.stringify(formState.values, null, 2)}</code>
  </pre>
 );
};

const App = () => (
 <div className="App">
  <Form>
  <div>
   <Input name="name" label="Name:" />
   <Input name="occupation" label="Occupation:" />
   <button type="submit">Submit</button>
  </div>
  <div>
   <h5>Component using formState:</h5>
   <ComponentUsingFormState />
  </div>
  </Form>
 </div>
);
```

In the code block above, in `ComponentUsingFormState`, you can access the form values by using the dot notation `formState.values`:

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/image_9dc29725c2922e2ee0dfc6687d1f16eb.png" alt="formState output with Informed."/><figcaption>formState output</figcaption></figure>

#### useFormApi

The `useFormApi` hook from the Informed library allows you to gain access to the form API functions. You can alter the value of an input using the functions that `formApi` provides for React form validation:

```
...

import { Form, Input, useFormApi } from "informed";

const RandomSetterButton = () => {
 const formApi = useFormApi();
 return (
  <button
   type="button"
   onClick={() =>
    formApi.setValue(
     "name",
     Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER))
    )
   }
  >
   Random
   </button>
 );
};

const SetValuesButton = () => {
 const formApi = useFormApi();
 return (
  <button
   type="button"
   onClick={() => formApi.setValues({ name: 'Asta', age: 26, color: "Green" })}
  >
   All
  </button>
 );
};

const SetTheseValuesButton = () => {
 const formApi = useFormApi();
  return (
   <button
    type="button"
    onClick={() => formApi.setTheseValues({ age: 27, color: "Yellow" })}
   >
    Age & Color
   </button>
  );
};

const App = () => (
 <Form onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))}>
  <div>
   <Input name="name" label="First Name:" />
   <Input name="age" label="First Name:" type="number"  />
   <Input name="color" label="Favorite Color:" />
   <RandomSetterButton />
   <SetValuesButton />
   <SetTheseValuesButton />
   <button type="submit">Submit</button>
  </div>
 </Form>
);

...
```

As shown in the code block above, the `RandomSetterButton` component uses `setValue` to target a single input. In this case, the name input is targeted, and the value is set to a random number. The `SetTheseValuesButton` component uses the `setTheseValues` function to change the values of name, age, and color inputs. Also, the `SetValuesButton` component uses `setValues` to set the input values of both age and color to different values. One of the important `useFormApi` functions is the `onSubmit` function. This gives you access to the form values, which can be used as payload to an endpoint.

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/WDn0u8N_2b8454070c66afd115c3f984a9b2a159.gif" alt="React form validation example."/><figcaption>useFormApi output</figcaption></figure>

#### useFieldApi

The `useFieldApi` hook gives you access to the field API functions using a dot notation:

```
...

import { Form, Input, useFieldApi } from "informed";

const ComponentUsingFieldApi = () => {
 const fieldApi = useFieldApi("name");
 return (
  <button
   type="button"
   onClick={() =>
    fieldApi.setValue(
     ' Math.floor(Math.random() * Math.floor(Number.MAX_SAFE_INTEGER))'
    )
   }
  >
   Random
  </button>
 );
};

const App = () => (
 <Form>
  <div>
   <Input name="name" label="Name:" initialValue="Joe" />
   <button type="submit">Submit</button>
   <h5>Component using fieldApi:</h5>
  <ComponentUsingFieldApi/>
  </div>
 </Form>
);

...
```

The `name` field having the `initialValue` Meliodas, changes to a random number when the random button is clicked:

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/avwYLXe_dd82415d01a7710c45e45acae0fbed64.gif" alt="useFieldApi output with Informed."/><figcaption>useFieldApi output</figcaption></figure>

#### useFieldState

The `useFieldState` hook gives you access to the field state attributes:

```
...

import { Form, Input, useFieldState } from 'informed';

const ComponentUsingFieldState = ({ name }) => {
 const fieldState = useFieldState(name);
 return (
  <>
   <h5>Component using fieldState: {name}</h5>
   Render: {Math.random()}
   <pre>
    <code>{JSON.stringify(fieldState, null, 2)}</code>
   </pre>
  </>
 );
};

const App = () => (
 <Form>
  <div>
   <Input name="name" label="Name:" />
   <Input field="age" label="Age:" type="number" />
   <button type="submit">Submit</button>
  </div>
  <div>
   <ComponentUsingFieldState name="name" />
   <ComponentUsingFieldState name="age" />
  </div>
 </Form>
);

...
```

From the code block above, the `name` field is passed into the `useFieldState` hook as an argument, and can be used to keep track of every name attribute in the form state:

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/hvklIM9_b8e43c66c73cc4111280b39496a47cdc.gif" alt="useField State example with Informed."/><figcaption>useFieldState</figcaption></figure>

### Form Validation Methods

#### Simple Validation

Informed forms provide the validate prop to handle field-level validation. You can pass in rules from a function to validate an input field, or mark it as `required`:

```
...

import { Form, Text } from 'informed';

const validate = (value) => {
 if (!value || value.length < 5)
  return (
   <span>Field must be at least five characters</span>
  )
};

const App = () => {
 return (
  <Form
   onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))}>
   <Input name="color" label="Color:" validate={validate} required />
   <Input name="food" label="Food:" validate={validate} />
   <button type="submit">Submit</button>
  </Form>
 );
};

...
```

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/xpU24pR_b8e9caf32610ac21957a8ba84ccc2f2c.gif" alt="An example of simple form validation with Informed."/><figcaption>Simple validation</figcaption></figure>

#### Validation Control

For more control when validating, passing `validateOn` props to fields makes Informed more flexible in handling React form validation. You can also choose to control when the error message shows using the `showErrorIfError`, `showErrorIfTouched`, and `showErrorIfDirty` props:

```
...

const App = () => (
  <div className="App">
  <Form
   onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))}
  >
   <div>

    <h4>validateOn="blur" ( default )</h4>
    <Input
     name="username1"
     label="Username1"
     required
     validate={validate}
    />
    <h4>validateOn="change"</h4>
    <Input
     name="username2"
     label="Username2"
     validateOn="change"
     required
     validate={validate}
    />
    <h4>validateOn="change" && showErrorIfDirty</h4>
    <Input
     name="username3"
     label="Username3"
     validateOn="change"
     showErrorIfDirty
     required
     validate={validate}
    />
    <h4>validateOn="change-blur"</h4>
    <Input
     name="username4"
     label="Username4"
     validateOn="change-blur"
     required
     validate={validate}
    />
    <h4>validateOn="change-submit"</h4>
    <Input
      name="username5"
      label="Username5"
      validateOn="change-submit"
      required
      validate={validate}
    />
    <h4>validateOn="blur-submit"</h4>
    <Input
     name="username6"
     label="Username6"
     validateOn="blur-submit"
     required
     validate={validate}
    />
    <h4>validateOn="submit"</h4>
    <Input
     name="username7"
     label="Username7"
     validateOn="submit"
     required
     validate={validate}
    />
    <h4>validateOnMount</h4>
    <Input
     name="username8"
     label="Username8"
     validateOnMount
     required
     validate={validate}
    />
    <h4>validateOnMount && showErrorIfError</h4>
    <Input
     name="username9"
     label="Username9"
     validateOnMount
     showErrorIfError
     required
     validate={validate}
    />
    <button type="submit">Submit</button>

   </div>
   <div>
    <Debug values errors invalid validating />
    <button type="submit">Submit</button>
   </div>
  </Form>
 </div>
);

...
```

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/hYdROXX_f82e14cb957c95b6929182cf6a7770af.gif" alt="An example of validation control in Informed."/><figcaption>Validation control</figcaption></figure>

#### Validation Messages

This method aids you in displaying custom error messages for built-in validations. You can achieve this feat by making use of the `errorMessage` prop:

```
...

import {
 Form,
 Input,
 Debug
} from 'informed';

const validate = value => {
 if (!value || value.length < 5)
  return 'Field must be at least five characters';
};

const App = () => (
 <Form
  errorMessage={{ required: 'This field is required for your profile!' }}
  onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))}>
  <Input
   name="name"
   label="First name:"
   required
   errorMessage="There is a problem with this field!"
  />
  <Input
   name="last"
   label="Last name:"
   required
   errorMessage={{ required: 'Last name is required!' }}
  />
  <Input name="favoriteColor" label="Favorite color:" required />
  <button type="submit">Submit</button>
  <Debug values errors invalid valid />
 </Form>
);

...
```

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/9TFKFal_6b0b47b8794c7c5d98f21c5203c38f7a.gif" alt="Sending validation messages with Informed."/><figcaption>Validation messages</figcaption></figure>

## Basic Form Validation

Informed allows you to create custom validation inputs that can be used across your application. Next, we’ll explore the `useField` and `useForm` hooks to create a custom form:

```
...

import { useForm, useField, Debug } from 'informed';

const CustomForm = ({ children, ...rest }) => {
 const { formController, render, userProps } = useForm(rest);

/* --- DON'T FORGET TO CALL THE RENDER METHOD FROM THE HOOK! --- */
return render(
 <form
  {...userProps}
  onReset={formController.reset}
  onSubmit={formController.submitForm}
  onKeyDown={formController.keyDown}>
  {children}
 </form>
 );
};

const CustomInput = props => {
 const { render, informed, fieldState, userProps, ref } = useField({
  type: 'text',
  ...props
 });

const { id, label, ...rest } = userProps;
 const { error, showError } = fieldState;

/* --- DON'T FORGET TO CALL THE RENDER METHOD FROM THE HOOK! --- */
return render(
 <>
  <label htmlFor={id}>{label}</label>
  <input
   {...rest}
   {...informed}
   ref={ref}
   style={showError ? { border: 'solid 1px red' } : null}
  />
   {showError && <small style={{ color: 'red' }}>{error}</small>}
  </>
 );
};

const App = () => (
 <div className="App">
  <CustomForm
   onSubmit={({ values }) => window.alert(JSON.stringify(values, null, 2))} 
  >
   <div>
    <CustomInput
     field="name"
     label="First name:"
     validateOn="change"
     required
     minLength={5}
    />
    <button type="submit">Submit</button>
   </div>
   <Debug values errors />
  </CustomForm>
 </div>
);

...
```

Using the `useField` and `useForm` hooks, a custom form and input component was generated in the code block above. When utilizing either hook, you must always call the render method obtained from both hooks:

<figure><img src="https://d37oebn0w9ir6a.cloudfront.net/account_32099/j3yYqiu_fe147621a5b320758df52aff9b15fb66.gif" alt="Using custom validations in Informed."/><figcaption>Custom Validation</figcaption></figure>

## Conclusion

In this article, we explored the Informed library for handling React form validation in applications. We also covered creating custom inputs and custom validation error messages. To see more of what the library offers, check their [docs](https://teslamotors.github.io/informed/?path=/story/introduction--getting-started) and [GitHub repository](https://github.com/teslamotors/informed).