DEV Community

Bill
Bill

Posted on • Updated on

React form validation with Hook in 5kB

TL;DR: Introducing a new React Hook library to deal with form validation with an easier and cleaner approach (IMHO).

I have been dealing with forms over the past years, whether it’s a single form submission or multiple steps funnel.

Recently React 16.8 have landed us with Hook, which in my opinion is one the greatest features that React team has been delivered🌹(Thank you React Team). Therefore, I have discovered a new approach to write form validation, potentially a cleaner approach. let me show you the code 🔎

import React from 'react'
import useForm from 'react-hook-form'

function App() {
  const { register, handleSubmit, errors } = useForm() // initalise the hook
  const onSubmit = (data) => { console.log(data) } // submission when input are valid

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstname" ref={register} /> // register input

      <input name="lastname" ref={register({ required: true })} /> // register as required field
      {errors.lastname && 'Last name is required.'} // display error message when last name is not valid

      <input name="age" ref={register({ pattern: /\d+/ })} />  // register as input with pattern
      {errors.age && 'Please enter number for age.'} // display error message when age is not valid

      <input type="submit" />
    </form>
  )
}
Enter fullscreen mode Exit fullscreen mode

As you can see from the example above, there is no Component have been imported. So instead of having controlled input/select over the form, this approach leverage uncontrolled form input and registering their ref into the React hook form. This allows the hook to have full control and insight over your form elements, and hence this reveal many other benefits:

  • No external Components required to wrap around inputs, which made the hook library much smaller (5kb gzip)
  • Because it’s uncontrolled, you are no longer required to have onChange and set value to your input, start leveraging your existing HTML markup.
  • With Component’s ref been registered into the Hook, you can easily access its ref when an error occurred, and anchors to the particular field.
  • Much simpler API, because validation occurs at the register level.
  • Great for performance as input change no longer trigger re-render, check out the performance comparison here.
  • Easy form state access, since Hook is holding refs for each input. you can easily query the value of them.
  • Support browser build-in validation ❤️.

Those are my summaries of benefits over using React Hook Form, I think with this approach, things are much simpler (IMHO). Please check out the website for a live demo, I have also built a form builder which allows you to create form and copy/paste code to your environment or codeSandbox to test them out. Many examples also live on the Github page.

I really hope this will make form validation easier, and feel free to leave me with issue or suggestion on Github (please leave a star if you find it useful 🙏🏻). ❤️ Thank you for reading.

Oldest comments (3)

Collapse
 
wnemencha profile image
William Nemencha

Amazing work! Thanks for sharing 👌

Collapse
 
bluebill1049 profile image
Bill

Thank you 😊

Collapse
 
ronnewcomb profile image
Ron Newcomb

Not bad. But not a fan of:

ref={register({
validate: {
positiveNumber: value => parseFloat(value) > 0,
lessThanHundred: value => parseFloat(value) < 200
}
})}

because it seems wordier than

ref={register({
positiveNumber: value => parseFloat(value) > 0,
lessThanHundred: value => parseFloat(value) < 200
})}

though I understand you are using keyword required in a different way, like

ref={register({
required: true,
maxLength: 80,
validate: {
positiveNumber: value => parseFloat(value) > 0,
lessThanHundred: value => parseFloat(value) < 200
}
})}

even though I think it would be OK to crush them together

ref={register({
required: true,
maxLength: 80,
positiveNumber: value => parseFloat(value) > 0,
lessThanHundred: value => parseFloat(value) < 200
})}

just to save client code keystrokes.

Also it's unclear to me how it maps values from form to model and back, espeically if the mapping isn't simple. Like, a checkbox that maps to a Date field, setting it to 60 days from now, or null, depending if the checkbox is checked.