React + Constraints API === Better Validations

omwri
3 min readFeb 20, 2020
Photo by Goran Ivos on Unsplash

In this blog, we’ll go over building a React component that uses the native browser Constraints Validity API.

Why build such a component, you might ask?

  • The Constraints API is a native way to do validations on form elements.It provides a clean interface and syntax.
  • Writing validations is a tricky adventure. It’s always better to have a good sword with you.
  • Because it’s fun.

What is the Constraints API?

The constraints API is provided by the browser platform to validate input elements. We usually perform such validations on blur or change events. When such events fire, we can read an object called validity on the event target and use it to perform validations.

The validity object contains various fields that correspond to the type of validation error.

Example Validity Object

{
valueMissing: false,
typeMismatch: true,
patternMismatch: false,
tooLong: false,
tooShort: false,
rangeUnderflow: false,
rangeOverflow: false,
stepMismatch: false,
badInput: false,
customError: false,
valid: false
}

For example, the typeMismatchfield would be set to trueif the user typed in an invalid email in an input field of type email. We can use these fields in our React component as well.

Component Design

const InputWithValidator = ({
id,
inputProps,
labelText,
checks,
errorMessage
}) => {
const [isValid, setIsValid] = useState(true);

const checkValidity = ev => {
const { validity } = ev.target;
const checksPassed = checks.filter(check => validity[check]).length === 0;
setIsValid(checksPassed);
};

return (
<Fragment>
<label htmlFor={id}>
{labelText}
</label>
<input id={id} {...inputProps} onBlur={checkValidity} />
<p className={`${isValid ? `dn` : `dib red`}`}>{errorMessage}</p>
</Fragment>
);
};
.dn {
display: none
}
.dib {
display: inline-block
}
.red {color: red}

For the React component, we have a label, an input tag, and a paragraph tag for the error message, which will be visible only when the input is invalid. We tap into the onBlur event handler of the input tag and perform validations. We pass the required validations as a prop to the input tag. We also have some basic classes for styling. The component also accepts custom messages.

The main piece of functionality is the checkValidity method that fires on blur. This function reads through the validity object and matches it with the passed validation checks. If all the checks pass, then each of the fields will be set to false in the validity object. Hence, the filter function will return an empty array. Conversely, even if one check fails, the filter function will return a non-empty array.

Based on this, we can make the call that the input is valid if and only if the filter function returns an empty array. We set the internal state of the component based on this assumption.

Let’s build an email validation. Here, we pass the typeMismatchas the required validation.

Similarly, we can create an input tag for a number that has a minimum and maximum limit. When the user types in a number that is above the maximum limit, we can show an error message by specifying the rangeOverflowvalidation. We can use the rangeUnderflowvalidation to check if the number is below the minimum limit.

Here’s an example of an input tag that is required, and we can show an error message when the user leaves the input field.

So, there you go: A cleaner approach to validations. Yet, this is only a glimpse into what the Constraints API offers. For full details, check out the MDN link below, and go forth to build awesome things.

--

--