Form Validation

Validate input and show helpful error messages with state.

With controlled inputs you can validate as the user types or on submit. Store any error messages in state and render them next to the field.

A simple approach

  1. Keep field values in state.
  2. On submit (or change), run your checks.
  3. Store errors in state and display them conditionally.

Always pair custom validation with proper HTML attributes like required and type="email" for accessibility and native support.

Example

Example Β· javascript
import { useState } from 'react';

function SignupForm() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');
  function handleSubmit(e) {
    e.preventDefault();
    if (!email.includes('@')) {
      setError('Please enter a valid email.');
      return;
    }
    setError('');
    console.log('Signed up', email);
  }
  return (
    <form onSubmit={handleSubmit}>
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      {error && <p>{error}</p>}
      <button>Sign up</button>
    </form>
  );
}

When to use it

  • A registration form validates the email field on blur and displays an inline error message under the field so the user gets feedback before hitting submit.
  • A password strength meter runs validation logic inside an onChange handler and shows a live strength bar without waiting for the form to be submitted.
  • A checkout form validates all fields on submit and focuses the first invalid input automatically to help keyboard-only users correct mistakes quickly.

More examples

Validate on submit

Validates the email on submit, stores the error message in state, and renders it conditionally below the input.

Example Β· jsx
import { useState } from 'react';

function SignupForm() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');

  function handleSubmit(e) {
    e.preventDefault();
    if (!email.includes('@')) {
      setError('Please enter a valid email address.');
      return;
    }
    setError('');
    console.log('Submitting:', email);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={email} onChange={e => setEmail(e.target.value)} type="email" />
      {error && <p className="error">{error}</p>}
      <button type="submit">Sign up</button>
    </form>
  );
}

Validate on blur

Runs validation when the user leaves the field (onBlur) so the error appears after they finish typing, not during.

Example Β· jsx
import { useState } from 'react';

function PasswordField() {
  const [value, setValue] = useState('');
  const [error, setError] = useState('');

  const validate = () =>
    setError(value.length < 8 ? 'Minimum 8 characters.' : '');

  return (
    <div>
      <input
        type="password"
        value={value}
        onChange={e => setValue(e.target.value)}
        onBlur={validate}
      />
      {error && <span className="error">{error}</span>}
    </div>
  );
}

Multi-field form validation

Validates multiple fields in a single validate function and stores all errors in one state object.

Example Β· jsx
import { useState } from 'react';

function ContactForm() {
  const [fields, setFields] = useState({ name: '', email: '' });
  const [errors, setErrors] = useState({});

  function validate() {
    const e = {};
    if (!fields.name.trim()) e.name = 'Name is required.';
    if (!fields.email.includes('@')) e.email = 'Invalid email.';
    return e;
  }

  function handleSubmit(evt) {
    evt.preventDefault();
    const e = validate();
    if (Object.keys(e).length) { setErrors(e); return; }
    console.log('Valid:', fields);
  }

  const update = key => e => setFields(f => ({ ...f, [key]: e.target.value }));

  return (
    <form onSubmit={handleSubmit}>
      <input value={fields.name} onChange={update('name')} placeholder="Name" />
      {errors.name && <p className="error">{errors.name}</p>}
      <input value={fields.email} onChange={update('email')} placeholder="Email" />
      {errors.email && <p className="error">{errors.email}</p>}
      <button type="submit">Send</button>
    </form>
  );
}

Discussion

  • Be the first to comment on this lesson.