Client-side form validation in React

Linked Projects:

Lesson code -

In this lesson, we'll see how to do form validations in the browser using React.

It’s important to do validations on the server before saving user-submitted data but there are some things we can do on the client to stop the user from submitting invalid data.

This saves the user time and makes for a better user experience.

In the previous lesson, we added a constraint on the appointment title - it needs to be at least 3 characters long. But we only check if the value entered by the user passes this validation once they submit the form. So it takes a round trip to the server to tell the user that there’s a problem with the data.

We can easily check for this in the client with React and give the user real-time feedback about validation.

We can disable the form submit button unless the form field values are valid.

Let’s do that with the title field first.

In our AppointmentForm component, let’s set the disabled attribute of the form submit button to a prop that we’ll pass to it.

<input type='submit' value='Make Appointment'
  disabled={!this.props.formValid} />

So we’ll pass this prop called formValid which is a boolean indicating whether the form is valid or not.

If it’s not valid we’ll set disabled to true, thus preventing the user from submitting the form.

We’re using this component in its parent Appointments component. So that’s where we need to pass the formValid prop.

Let’s add it in appointments.jsx:

<AppointmentForm input_title={this.state.title}
  onUserInput={(obj) => this.handleUserInput(obj)}
  onFormSubmit={() => this.handleFormSubmit()} />

We’ll save formValid in the state.

Let’s set its initial value to true in the constructor:

  constructor (props, railsContext) {
    this.state = {
      appointments: this.props.appointments,
      title: 'Team standup meeting',
      appt_time: '3 March 2018',
      formErrors: {},
      formValid: true

Now, we need to watch for the user input in the title field and update the state value formValid based on the length of the input.

We already have the handleUserInput function which updates the state with the value of the input.

  handleUserInput (obj) {

So let’s modify that to also trigger a validation.

The setState function accepts a second optional argument which is a callback function that’s executed once setState is completed and the component is re-rendered.

So we can pass a validation function as the second optional argument to setState. Let's call it validateForm.

  handleUserInput (obj) {
    this.setState(obj, this.validateForm);

And let’s define that function as:

validateForm() {
  this.setState({formValid: this.state.title.length > 2});

Now let’s see if this works in the browser.

If we clear the default value in the title input field and try to submit the form, we can’t submit it. 

But it’s not obvious because the button looks the same. There’s no visual feedback so we can’t tell if it’s working or not.

Let’s fix that by adding a bit of CSS for the disabled state of the button:

.submit-button:disabled {
  background: #bbb;
  cursor: not-allowed;
We’ve set the background colour to a light grey and changed the cursor type to not-allowed.

Now when we clear the default value, the button looks disabled.

Disabled form submit button

If we type, it gets enabled again as soon as we type in 3 characters.

But we can still submit a blank value if we just type 3 spaces, so let’s fix that by adding the trim function to our validation function:

validateForm() {
  this.setState({formValid: this.state.title.trim().length > 2});

Now, spaces at the beginning and end of the input value get trimmed before the length validation, so we can’t submit a blank value.

Ok, so that’s a simple text field client side validation in React.

In the next lesson, we’ll generalise the validation and also add one for the appointment time field.

Liked this tutorial? Get more like this in your inbox