Controlled Component Pattern

Overview

In a controlled component, form data is handled by a React component's state. The component renders a form, but the form's state lives in the React component's state and is updated through callbacks like onChange. This gives you complete control over the form's behavior.

Example

Controlled Form

Controlled Component Example

This form demonstrates controlled components where React manages the form state.

Current Form State:

{
  "name": "",
  "email": "",
  "message": ""
}

Current State Value

{
  "name": "",
  "email": "",
  "message": ""
}

Code Implementation

// ControlledForm.tsx
import React from "react";

interface ControlledFormProps {
  values: {
    name: string;
    email: string;
    message: string;
  };
  onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
  onSubmit: (e: React.FormEvent) => void;
}

export const ControlledForm: React.FC<ControlledFormProps> = ({
  values,
  onChange,
  onSubmit
}) => {
  return (
    <form onSubmit={onSubmit} className="space-y-4">
      <div>
        <label htmlFor="name" className="block mb-1 text-sm font-medium">
          Name
        </label>
        <input
          type="text"
          id="name"
          name="name"
          value={values.name}
          onChange={onChange}
          className="w-full p-2 border rounded focus:ring focus:ring-blue-200"
          required
        />
      </div>
      
      <div>
        <label htmlFor="email" className="block mb-1 text-sm font-medium">
          Email
        </label>
        <input
          type="email"
          id="email"
          name="email"
          value={values.email}
          onChange={onChange}
          className="w-full p-2 border rounded focus:ring focus:ring-blue-200"
          required
        />
      </div>
      
      <div>
        <label htmlFor="message" className="block mb-1 text-sm font-medium">
          Message
        </label>
        <textarea
          id="message"
          name="message"
          value={values.message}
          onChange={onChange}
          rows={4}
          className="w-full p-2 border rounded focus:ring focus:ring-blue-200"
          required
        />
      </div>
      
      <button
        type="submit"
        className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
      >
        Submit
      </button>
    </form>
  );
};

Key Benefits

  • Complete control over form inputs and their values
  • Instant access to input values for validation or conditional rendering
  • Ability to enforce input formats and transformations
  • Synchronized UI state with form data
  • Predictable form behavior and easier testing