Skip to content

Forms

intermediate2 min read
  • React
  • TypeScript

Handling user input in React with controlled components, where form state lives in the component and drives each input, plus validating before submit.

Prerequisites

  • State and events (see Related Topics)

What you'll understand

  • What a controlled component is
  • How form state connects an input to React
  • How to handle submission and validate input

Explanation

Forms are how users give data to your app, and React handles them through controlled components. In a controlled input, the value shown comes from state, and every keystroke fires an onChange handler that updates that state (see Related Topics). React becomes the single source of truth for what the input contains, rather than the DOM holding its own separate value.

This pattern is powerful because the current form data always lives in your component. You can validate it as the user types, enable or disable the submit button based on it, transform it, or pre-fill it, all by reading and writing ordinary state. The input simply reflects whatever the state says.

Submission is handled with an onSubmit handler on the form, and you call preventDefault to stop the browser from doing a full-page reload. Client-side validation here gives the user quick feedback, but it is only a convenience: it can be bypassed, so the server must still validate every submission independently (see Related Topics). The browser and the server each do their own checking.

Examples

A controlled input keeps its value in state and updates on every change; submit is handled with preventDefault:

import { useState } from 'react';

function EmailForm() {
  const [email, setEmail] = useState('');

  function handleSubmit(e: React.FormEvent) {
    e.preventDefault(); // stop the full-page reload
    if (!email.includes('@')) return; // quick client-side check
    save(email);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <button type="submit">Save</button>
    </form>
  );
}

Common mistakes

  • Setting an input value from state but forgetting onChange, making it read-only.
  • Forgetting preventDefault, so the form reloads the whole page on submit.
  • Trusting client-side validation alone and skipping server validation (see Related Topics).
  • Storing each field in a separate unmanaged place instead of component state.

Best practices

  • Use controlled components so React owns the form data.
  • Update state on change and read it on submit.
  • Call preventDefault in the submit handler.
  • Validate on the client for feedback, but always validate again on the server (see Related Topics).

Further reading

Related topics