Validating forms shouldn’t be so rough. It’s something almost every website should be doing. Sure, you have those nice HTML5 input types now, and a
required flag, but that doesn’t get you far when you have design and business requirements to deal with.
As with most hard problems, there has been a lot of attempts by the community to solve this. Most notably is the
redux-form project, which places all of your form state in a Redux reducer, and passes you all the form values on submit. It works well for its intended purpose — but it still leaves you implementing the actual validation.
There are tons of great validation libraries out there too. My favorite for a long time was
validation. You pass some input, and you get a boolean back indicating whether or not the value is valid according to the given validator.
The problem with this approach is that you’re still left implementing a lot of logic! You have to create some kind of way to show error messages, support live validation, multiple validation rules per field and compound validation that depends on other fields.
Relax buddy, I got you.
I — much like yourself — have squabbled with this challenge quite a few times, and I think I’ve created something that solves all of the issues I’ve come across with form validation in React. I named it
calidation, because it provides you with red hot form validation peppers for React. 🌶
You specify the names of the fields you want to use, the validators you want to run and the error messages you want to show the user if the input fails its validation. You then replace your crusty old
<form /> tag with a fancy new
<FormValidation /> component, pass in your configuration object and a few other props (like an
onSubmit handler), and lean back.
In order to provide you — the consumer — with the ultimate amount of flexibility,
calidation uses a render prop to pass you the validation results. That means it’s still up to you to show error messages, control components and whatever else you want to do with the result.
Here’s a complete, working example:
Notice that the inputs aren’t controlled? That’s right! The
<FormValidation /> component uses event bubbling to capture any
change events below it, and runs any validation logic every time.
Live validation by default!
Running the validation logic on every change event continuously, means you’ll always have up-to-date validation results — or what we often call “live validation”. It’s typically what you encounter after you’ve submitted a form, gotten some errors and see your error message instantly disappear whenever you correct your error.
Showing errors all the time, even before the user has started typing, is not a good user experience. Luckily, you’re in charge of what to render — so you can choose to only show those errors after the form has been submitted.
This way, the errors won’t show up until you submit it! Perfect 👊
Validators validators validators!
calidation comes pre-packaged with its own set of validators — aptly named
calidators (I was on a roll). It doesn’t contain much, but enough to deal with most of your validation needs.
calidators small on purpose — there is no way I could ever cover all validation needs. What about social security numbers, Norwegian mobile phone numbers or HSLA color codes?
calidation is extendable with all the validators you want. Wrap your application in a
<ValidatorProvider /> component, and pass in all your custom magic there. Refer to the
calidators docs on how to write them.
Sometimes, this approach with all input fields inside the same form is a bit of a pain. Perhaps your form is just too big or complicated? Perhaps there are several steps, and each step depends on previous ones? I’ve come across this too, and this is where this library (in my humble, very objective opinion) really shines.
Instead of having a single
<FormValidation /> component, we split up the form itself and each subset of validation into two components —
<Form /> and
<Validation /> .
<Form /> component accepts an
onSubmit handler, which receives the compound set of input values from all
<Validation /> components. The
<Validation /> components each get their piece of the
config object that’s relevant to them.
<Validation /> components can be anywhere, as long as they are descendants of the
<Form /> — so you don’t have to do a ton of prop drilling to pass stuff down.
Here’s a bit more complex example with two sub forms:
Try it out!
If you’re dealing with form validation in React, give this a try and tell me what you think. It’s free, open source and just waiting for you to npm install it.
$ npm install calidation