← Back to React Course | Chapter 7: Forms & User Input | Lesson 3 of 8

Client-Side Form Validation

Form validation is like a teacher checking your homework before accepting it, telling you exactly what to fix if something's wrong.

Writing a Simple Validation Function

A validation function takes the current form values and returns an object describing what's wrong, if anything. Keeping validation logic in a plain function (separate from JSX) makes it easy to test and reuse.

Note: Return an empty object (no errors) when everything is valid, so 'Object.keys(errors).length === 0' means the form is valid.

Warning: Don't put validation logic directly inside JSX — it gets hard to read and impossible to reuse.

Example: Writing a Simple Validation Function

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
function validate(email) {
  if (!email) return "Email is required";
  if (!email.includes("@")) return "Email must contain @";
  return "";
}
function App() {
  const [email, setEmail] = React.useState("");
  const error = validate(email);
  return <div><input value={email} onChange={e => setEmail(e.target.value)} /><p style={{color: "red"}}>{error}</p></div>;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>

Showing Errors Only After the Field Is Touched

Showing 'Email is required' before the user has even typed anything feels aggressive. Tracking a touched state per field, set to true on blur, lets you delay showing errors until the user has actually interacted with that field.

Note: onBlur (fires when a field loses focus) is the standard place to mark a field as touched.

Warning: Forgetting to check touched before showing an error means every field shows red before the user does anything.

Example: Showing Errors Only After the Field Is Touched

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
function App() {
  const [email, setEmail] = React.useState("");
  const [touched, setTouched] = React.useState(false);
  const error = !email ? "Email is required" : "";
  return (
    <div>
      <input value={email} onChange={e => setEmail(e.target.value)} onBlur={() => setTouched(true)} />
      {touched && <p style={{color: "red"}}>{error}</p>}
    </div>
  );
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>

Disabling Submit Until the Form Is Valid

A submit button's disabled prop can be tied directly to whether the form currently has errors. This gives an immediate visual signal and prevents invalid submissions entirely, rather than relying only on an error message.

Note: Combine this with showing errors on touch so the button being disabled doesn't feel mysterious to the user.

Warning: Disabling the button isn't a substitute for server-side validation — always re-validate on the backend too.

Example: Disabling Submit Until the Form Is Valid

markup
<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/react@18/umd/react.development.js"></script>
  <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
  <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
  <div id="root"></div>
  <script type="text/babel">
function App() {
  const [email, setEmail] = React.useState("");
  const isValid = email.includes("@");
  return (
    <div>
      <input value={email} onChange={e => setEmail(e.target.value)} />
      <button disabled={!isValid}>Submit</button>
    </div>
  );
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  </script>
</body>
</html>
Common Mistakes
  1. Validating only on submit and never giving feedback while the user is still typing.
  2. Showing all error messages before the user has even touched the form.
  3. Not disabling the submit button when the form is invalid, letting users submit bad data anyway.
Chapter Summary
  • Client-side validation checks form values against rules (required, format, length) before submission.
  • Validation can run on every change, on blur, or only on submit, each with different UX tradeoffs.
  • Storing an errors object alongside form state lets you show field-specific messages.
  • Disabling the submit button based on validity prevents obviously-invalid submissions.
Browser Support

No React-version restriction — pure JavaScript validation logic works in any supported React version.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.