In the first part of this article I proposed implementing form validation/submission in vanilla React (no 3rd party libraries) using HTML5 and Constraint API.
The code example provided was intentionally simple to make the point that, if you build the feature on top of the native implementation, then you:
- only need to write a fraction of code to handle forms
- don’t need to learn how to use a new library
- get a lighter JS bundle
- reduce the number of dependencies
- you don’t need to write tests for the validation fn, it’s already been tested!
This time I would like to add a less trivial component to our form: the password field.
The end product will look like this:
and the interactive demo is available here.
The password field in our form is responsible for validating the user input, testing it against the following 5 validation rules:
- at least one Uppercase
- at least one digit
- at least 8 characters
- at least one special character
It also comes with the show/hide password button to toggle the password visibility.
The password component is built on top of the TextInput component we already implemented in part one. The only thing I added was the RhsComponent prop to inject the show/hide button:
The PlainTextToggle is just a button that toggles isPlainText state var between true and false. This in turn switches the input type between “text“ and “password”. I am not going to discuss this implementation further has it’s not in the scope of this article.
All the validation magic comes courtesy of the pattern prop!
As we know HTML5 allows for custom validation through the use of the pattern property. Pattern needs to be a valid RegEx… or the combination of multiple RegExes.
I am no expert when it comes to writing regular expressions so I googled around and found the following four (utils/validationRules.ts):
The first four lines in the above screenshot implement 4 of our requirements. The PASSWORD_VALID_REGEX further down is the combination (in logical AND) of the those four RegExes and that is what we are going to set in the password pattern property.
Please note that the password component is just this:
and, as we said, it’s pattern attribute is PASSWORD_VALID_REGEX i.e. the string that combines the 4 RegExes.
The fifth validation rule, required, is enforced by the “required” HTML attribute as we already saw when we implemented the name and email fields.
This code alone already implements all of our requirements!
Let me repeat this again: to implement all of the 5 validation rules we just need to provide one string and one attribute!
This is all this component needs to do: to get the user input and validate it against the pattern that comes out of the composition of 4 simple regular expressions. No more, no less than what the Tel field does in our form.
If it wasn’t for the show/hide toggle component then the password component code would have looked like this:
To improve the UX and provide visual feedback of the validation process we are now going to add the CheckList component:
It gets the password the user types in and runs it through the four RegExes to check which one is satisfied.
We start defining an array (rules) that gets mapped to an array of tags. If the pattern is matched then we add the “passed” className to tweak the style.
Next step is to compose the PasswordInput and the CheckList components. We do this in the PasswordWithChecklist:
It simply funnels the password value it gets from PasswordInput into CheckList.
Our App.tsx now looks like:
Just one line taller than the one we have in part-one :)