React Form: Handling User Inputs

When building a web application, we will eventually have to handle user inputs through forms. Forms are central to creating web application, as they are what enable users to transfer information from their head into our application. In this post we will learn two ways React application can handle user inputs.

Controlled Inputs

In controlled inputs, we basically let React state to save the values of our input elements. The component that renders our form will also handle any change in input values by our users subsequent input. This sample code shows the most simple controlled input component

class ControlledInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e){
    this.setState({
      value: e.target.value 
    })
  }
  render(){
    return(
      <input onChange={this.handleChange} value={this.state.value}/>
    )
  }
}

Each time the user type a new character into the input element, the onChange prop will be triggered. It will run the handleChange function, which set the state of the component to match the value of input element. This is the "React way" of handling user inputs, in which React "control" the value of the input element from state, and when state value is changed, the value of input element will be updated as well.

By controlling the input value, React ensures that our application data (or state) and UI (the input elements) will always be in sync. State gives input a value, and input ask for state update when onChange event is triggered — input onChange event will trigger on every keystroke.

How controlled input works
How controlled input works

With the input elements being controlled through React state, modifying or validating user inputs become a straightforward process. For example, we can give validation immediately on every keystroke.

class ControlledInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: '',
      value_error: '',
    };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    let error_message = ''
    // check if input is a valid email using regex
    if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.target.value)) {
      error_message = 'Please enter a valid email address. For example "example@example.com".'
    }
    this.setState({
      value: e.target.value,
      value_error: error_message,
    })
  }
  render(){
    return(
      <>
      <label> Email:
        <input onChange={this.handleChange} value={this.state.value}/>
      </label>
      <div style={{color: "red"}}>{this.state.value_error}</div>
      </>
    )
  }
}

JSX input elements use value attribute for text, textarea and select tag. For radio and checkbox it uses checked attribute. We can see their differences in the table below:

input type value attribute event target property
<input type="text"/> value={string} event.target.value
<textarea /> value={string} event.target.value
<select /> value={option value} event.target.value
<input type="radio"/> checked={boolean} event.target.checked
<input type="checkbox"/> checked={boolean} event.target.checked

Another things we can do using Controlled inputs are:

  1. Enforcing specific input formats like credit card numbers
  2. Disabling submit button until after all required inputs have values
  3. Conditional logic for rendering inputs based on values picked by users

conditional field example

Conditional logic example. Source: WordPress Plugin

So as we can see, controlled inputs give us developers powerful choices in how we make our form works. But what if we don't need all this extra stuff? What if all I want is to make a newsletter signup form with just one input? Then perhaps you can consider using the second way to create forms in React — the uncontrolled inputs

Uncontrolled Inputs

are very much like how form is handled in traditional HTML. Our React application doesn't bother with inputs until the submit button is clicked. Instead of controlling every input, we can instead just hook the form into React by using a ref attribute in the JSX. Like in regular HTML, we will get the value of input through its name. Consider the line below the comments:

class UncontrolledInput extends React.Component {
  constructor(props) {
    super(props)
    this.handleSubmit = this.handleSubmit.bind(this)
    // initialize ref
    this.form = React.createRef()
  }

  handleSubmit(e) {
    e.preventDefault()
    let message = ''
    //ref has all DOM element children of form in its current property
    if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(this.form.current.email.value)) {
      message = 'Please enter a valid email address. For example "example@example.com".'
      alert(message)
    } else {
      message = 'This is a valid email address :)'
      alert(message)
    }
  }
  render(){
    return(
      // put ref attribute into the form element
      <form onSubmit={this.handleSubmit} ref={this.form}>
        <label>
          Email:
          <input type="text" name="email" placeholder="enter your email"/>
        </label>
        <input type="submit" value="Submit" />
      </form>
    )
  }
}

Uncontrolled way of handling form inputs in React means we only retrieve input value on submit. This is particularly useful when we are converting a pre-existing app into React, when we don't need to write event handler for every input change in the form.

So which one to use?

Since we're talking about developing apps with React, I'd say it's better to always use controlled inputs whenever we can. Both methods works well in the situation they are meant to be used. If your form is incredibly simple in terms of UX and UI, you can go with uncontrolled input. But for administrative application where we have to gather information and make many input fields, it's better to use controlled inputs.

I will summarize their features here:

Feature Uncontrolled Controlled
onSubmit validation or function process
onChange validation or function process
conditional logic
input format enforcement

Get my weekly newsletter ✉️
Let's explore the exciting world of React together.
No Spam. Unsubscribe anytime