Learn More

Try out the world’s first micro-repo!

Learn More

How to Validate Forms in React Using Informed

How to Validate Forms in React Using Informed

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 form validation in web applications, and Informed is one such tool.

What Is Informed?

Informed is a form validation tool used in React 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 finally resolves the hassle of handling form state.

Getting Started With Informed

This section will walk you through integrating the Informed validation library into your React application, along with validating fields and creating custom inputs. In addition, we'll create a React application and install the Informed library by performing any 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;
}

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 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.

Basic Informed

Validation Hooks

The Informed library has a variety of hooks that help with various parts of managing simple to complex forms in your React 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:

formState output

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 formApi provides:

...

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.

useFormApi output

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:

useFieldApi output

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:

useFieldState

Validation Methods

Simple Validation

Informed provides 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>
);
};

...
Simple validation

Validation Control

For more control when validating, passing validateOn props to fields makes it more flexible in handling form validation. You can also choose to control when the error message shows using 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>
);

...
Validation control

Validation Messages

This method aids you in displaying custom error messages for the 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>
);

...
Validation messages

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 with the code block above. When utilizing either hook, you must always call the render method obtained from both hooks:

Custom Validation

Conclusion

In this article, we explored the Informed library for handling 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 and GitHub repository.

Interested in becoming a Pieces Content Partner?

Learn More

Get our latest blog posts and product updates by signing up for our monthly newsletter! 

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Table of Contents

Form

Validation

More from Pieces