Self-paced

Explore our extensive collection of courses designed to help you master various subjects and skills. Whether you're a beginner or an advanced learner, there's something here for everyone.

Bootcamp

Learn live

Join us for our free workshops, webinars, and other events to learn more about our programs and get started on your journey to becoming a developer.

Upcoming live events

Learning library

For all the self-taught geeks out there, here is our content library with most of the learning materials we have produced throughout the years.

It makes sense to start learning by reading and watching videos about fundamentals and how things work.

Search from all Lessons


← Back to Lessons

React Forms: Controlled Components and State Management

What Are Controlled Components?
  • How Controlled Components Work

What Are Controlled Components?

A controlled component is a form element whose value is controlled by React state. The component doesn't maintain its own internal state; instead, it relies on props passed from its parent component.

This pattern follows React's "single source of truth" principle, where the component state is the authoritative data source.

How Controlled Components Work

  1. Form element receives its current value from React state
  2. Updates to the value happen through change handlers that update state
  3. The render function reflects the current state value in the UI

Implementing Controlled Components

Here's a basic example of a controlled text input:

1import React, { useState } from "react"; 2 3function ControlledInput() { 4 const [value, setValue] = useState(""); 5 6 const handleChange = (event) => { 7 setValue(event.target.value); 8 }; 9 10 return ( 11 <div> 12 <input type="text" value={value} onChange={handleChange} /> 13 <p>Current value: {value}</p> 14 </div> 15 ); 16}

Notice these key characteristics:

  • The input's value attribute is set to a state variable
  • An onChange handler updates the state when the user types
  • The current value is immediately available for rendering or processing

Complex Form Management

For forms with multiple fields, you can use a single state object:

1import React, { useState } from "react"; 2 3function RegistrationForm() { 4 const [formData, setFormData] = useState({ 5 firstName: "", 6 lastName: "", 7 email: "", 8 password: "" 9 }); 10 11 const handleChange = (event) => { 12 const { name, value } = event.target; 13 setFormData({ 14 ...formData, // Preserve existing form data 15 [name]: value // Update only the changed field 16 }); 17 }; 18 19 const handleSubmit = (event) => { 20 event.preventDefault(); 21 console.log("Form submitted:", formData); 22 // Process the form data (e.g., API call) 23 }; 24 25 return ( 26 <form onSubmit={handleSubmit}> 27 <div> 28 <label htmlFor="firstName">First Name:</label> 29 <input 30 type="text" 31 id="firstName" 32 name="firstName" 33 value={formData.firstName} 34 onChange={handleChange} 35 /> 36 </div> 37 38 <div> 39 <label htmlFor="lastName">Last Name:</label> 40 <input 41 type="text" 42 id="lastName" 43 name="lastName" 44 value={formData.lastName} 45 onChange={handleChange} 46 /> 47 </div> 48 49 <div> 50 <label htmlFor="email">Email:</label> 51 <input 52 type="email" 53 id="email" 54 name="email" 55 value={formData.email} 56 onChange={handleChange} 57 /> 58 </div> 59 60 <div> 61 <label htmlFor="password">Password:</label> 62 <input 63 type="password" 64 id="password" 65 name="password" 66 value={formData.password} 67 onChange={handleChange} 68 /> 69 </div> 70 71 <button type="submit">Register</button> 72 </form> 73 ); 74}

Handling Different Input Types

Controlled components work with all HTML form elements. Here are some common examples:

Checkbox

1function ControlledCheckbox() { 2 const [isChecked, setIsChecked] = useState(false); 3 4 return ( 5 <label> 6 <input 7 type="checkbox" 8 checked={isChecked} 9 onChange={(e) => setIsChecked(e.target.checked)} 10 /> 11 I agree to the terms 12 </label> 13 ); 14}

Radio Buttons

1function ControlledRadioGroup() { 2 const [selectedOption, setSelectedOption] = useState("option1"); 3 4 const handleOptionChange = (e) => { 5 setSelectedOption(e.target.value); 6 }; 7 8 return ( 9 <div> 10 <label> 11 <input 12 type="radio" 13 value="option1" 14 checked={selectedOption === "option1"} 15 onChange={handleOptionChange} 16 /> 17 Option 1 18 </label> 19 20 <label> 21 <input 22 type="radio" 23 value="option2" 24 checked={selectedOption === "option2"} 25 onChange={handleOptionChange} 26 /> 27 Option 2 28 </label> 29 </div> 30 ); 31}

Select Dropdown

1function ControlledSelect() { 2 const [selectedValue, setSelectedValue] = useState("apple"); 3 4 return ( 5 <select 6 value={selectedValue} 7 onChange={(e) => setSelectedValue(e.target.value)} 8 > 9 <option value="apple">Apple</option> 10 <option value="banana">Banana</option> 11 <option value="orange">Orange</option> 12 </select> 13 ); 14}

Real-time Feedback and Validation

A major advantage of controlled components is the ability to provide immediate feedback to users:

1function ValidatedInput() { 2 const [email, setEmail] = useState(""); 3 const [isValid, setIsValid] = useState(true); 4 5 const validateEmail = (email) => { 6 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; 7 return emailRegex.test(email); 8 }; 9 10 const handleChange = (e) => { 11 const newEmail = e.target.value; 12 setEmail(newEmail); 13 setIsValid(validateEmail(newEmail) || newEmail === ""); 14 }; 15 16 return ( 17 <div> 18 <input 19 type="email" 20 value={email} 21 onChange={handleChange} 22 style={{ borderColor: isValid ? "initial" : "red" }} 23 /> 24 {!isValid && <p style={{ color: "red" }}>Please enter a valid email address</p>} 25 </div> 26 ); 27}

Best Practices for Controlled Components

  1. Use descriptive state names that match your form fields
  2. Create reusable form components for common input types
  3. Implement field-level validation for immediate user feedback
  4. Add appropriate HTML attributes (required, min, max, etc.) for accessibility
  5. Provide clear error messages when validation fails
  6. Include loading states during form submission

Conclusion

Controlled components give you precise control over form behavior in React applications. By connecting form elements to React state, you can:

  • Instantly access and validate input values
  • Dynamically disable/enable form controls
  • Format or sanitize user input on the fly
  • Implement multi-step forms with preserved state
  • Control exactly when and how the UI updates

While they require more initial code than uncontrolled components, the benefits of controlled components far outweigh the costs for most applications, especially those with complex forms or validation requirements.