Form validation user experiences: from worst to best (with React examples)

Saunved
helpshift-engineering
5 min readJul 19, 2022

--

Photo by Hal Gatewood on Unsplash

If you are a front-end developer, you must have created at least one form in your life. And it probably wasn’t a pleasant experience.

Forms can be hard to get right, especially when they have multiple sections or questions. Dynamic forms (forms that add or remove fields as the user progresses through them), can be quite challenging, too. With forms, things can get pretty difficult, pretty fast, especially if you haven’t made many of them before.

In this post, we are going to look at the different types of form validation user experiences. From the absolute worst, to possibly the best, we will discuss some hybrid strategies you could employ to give your end-users the best possible experience.

Let’s get started.

No validation

Let’s be honest. The worst form validation UX would be one which has no front-end validation at all. Your user clicks on the Submit button, and nothing changes. The form stays the way it is, and your user has no idea what went wrong.

Pre-validation

Pre-validation is when you show the form in an error state at the very beginning, and the user has to type everything out while the form is in an error state.

This does serve the purpose of validating the form, but it’s not ideal because you’re making the user feel bad about something they haven’t even done yet.

Eager validation

Eager validation is when you validate the user as soon as they start typing.

As you can imagine, it can be quite patronizing for the user. Many users already know how to fill up common fields (such as emails), so blaring an error message while they’re still typing can be quite the anxiety trip.

Validation on submit

In this user experience flow, you would typically show validation errors after the user clicks on Submit. This scenario works out well for small forms, but if your form has multiple sections, or many questions, this can be frustrating for the user.

They may have to back track, potentially scroll across a bunch of sections, and fix their errors for longer forms.

Validation at the field level

Validation at the field level is when you show an error message (if applicable) after the user moves to the next field.

With this method, the user gets quick feedback, but not so quick that they would feel patronized.

It does come with some drawbacks which can be solved with some hybrid approaches (which we will look at next).

Hybrid approach: Field-level + validating on submit

In the previous approach — what happens if the user submits the form without actually going to any field?

Well, the form would get submitted. Ideally, what we want to do in that case is show the field-level errors once the user clicks on Submit.

The Storybook example and React code for this hybrid approach is the same as the one in the previous example.

Hybrid approach: Field-level + eager validation + validating on submit

If you had observed the field validation example carefully, you would have noticed a problem.

When the user typed in a small password and shifted away, the error showed up (which is great). However, when the user went back to the password field and fixed their error, the error message did not go away. This can be quite misleading and frustrating for users.

The best UX would be to do the following:

  • If the user hasn’t yet entered any message, don’t show any validation message
  • When the user types something and moves away, validate the field
  • When the user types something on an erroneous field, perform eager validation on it

Fields where the user has already typed are often known as dirty fields. To summarize the above approach, we are doing field level validation, and also validating dirty fields eagerly.

With this approach, you can technically disable the “Submit” button altogether if you detect that a field is invalid in the form.

Notes and some bonus tips!

  • The Submit button in these examples doesn’t really do anything. It’s just there for demo purposes.
  • One would ideally debounce any onInputChange events to ensure that performance isn’t impacted on slower devices
  • You can use form libraries to get a lot of form boilerplate out of the way. Many libraries also offer different types of validation experiences based on your use-cases.
  • The way the form inputs are generalized in the code is probably not how you would do it in production — but this method was the easiest for code reuse
  • There are many ways of showing an invalid field. You can use icons, input borders, label messages, etc.
  • It’s important to optimize the language around your validation messages. They need to be clear and simple. I might write a separate post about this in the future.
  • You might have observed in the code that I have separated out all the strings in the app into their file (as constants). This is a good practice to ensure that your app is ready for translation when the day comes.
  • You can employ different approaches for different form fields. For example, you could make password validation “eager”, but keep email validation at a field-level. This is because password policies can vary across different websites, and a quicker feedback cycle here can help your user fill out the form faster. This decision should be taken after careful user studies to understand the best approach.

Useful links

  • Github repository (leave a star if you learned something new ⭐️ 🚀 and you are welcome to open a PR if you wish to add more examples or fix bugs)
  • Storybook dashboard (you might have to refresh before trying out each new component)

--

--

Saunved
helpshift-engineering

I write about life experiences, tech, and productivity