reactjs
/

Controlled Components – Managing Form State in React

Last Sync: Today

On this page

4
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

reactjs

Controlled Components – Managing Form State in React

The 'Single Source of Truth' Pattern

In a controlled component, the form data is handled by a React component. The alternative is uncontrolled components, where form data is handled by the DOM itself. In a controlled component, the input's current value is always driven by the React state, making the state the 'single source of truth'.

How Controlled Components Work

Every state mutation has an associated handler function. When a user types into an input, an event is triggered, the handler updates the state, and the component re-renders with the new value.

React JSXRead-only
1
import { useState } from 'react';

function NameForm() {
  const [name, setName] = useState('');

  const handleChange = (e) => {
    // Intercept and transform if needed
    setName(e.target.value.toUpperCase());
  };

  return (
    <input 
      type="text" 
      value={name} 
      onChange={handleChange} 
    />
  );
}

Why Use Controlled Components?

  • Instant Validation: You can check if an input is valid on every keystroke and show error messages immediately.
  • Conditional UI: Disable the 'Submit' button or show/hide fields based on the current value of another input.
  • Input Formatting: Automatically format inputs (like credit card numbers or phone numbers) as the user types.
  • Predictability: Since the state holds the data, the UI and the data are always in sync.

Handling Multiple Inputs

Instead of creating separate handlers for every field, you can use a single change handler by leveraging the name attribute of the HTML elements.

React JSXRead-only
1
const [formData, setFormData] = useState({
  username: '',
  email: ''
});

const handleInputChange = (e) => {
  const { name, value } = e.target;
  setFormData({
    ...formData,
    [name]: value // Computed property name
  });
};

Try it yourself

import React, { useState } from 'react';

function LivePreview() {
  const [text, setText] = useState('');

  return (
    <div style={{ padding: '20px' }}>
      <h3>Controlled Input Demo</h3>
      <input 
        type="text" 
        value={text} 
        onChange={(e) => setText(e.target.value)} 
        placeholder="Type something..."
        style={{ padding: '8px', width: '200px' }}
      />
      <div style={{ marginTop: '20px', color: '#666' }}>
        <strong>Live Preview:</strong> {text || '(empty)'}
      </div>
      {text.length > 10 && (
        <p style={{ color: 'red' }}>Warning: Text is getting long!</p>
      )}
    </div>
  );
}

export default LivePreview;

Test Your Knowledge

Q1
of 3

In a controlled component, what is the 'single source of truth'?

A
The DOM
B
The Browser Cache
C
React State
D
The URL parameters
Q2
of 3

Which prop is required to link an input's display to React state?

A
name
B
id
C
value
D
ref
Q3
of 3

How do you handle updates in a controlled component?

A
Through the onSubmit event only
B
Using the onChange event handler
C
Using a direct DOM query
D
React handles it automatically without code

Frequently Asked Questions

Is it slow to re-render on every keystroke?

For most standard forms, React's reconciliation is fast enough that users won't notice. For massive forms (100+ inputs), you might consider optimization or an uncontrolled approach.

What happens if I provide a 'value' prop without 'onChange'?

The input will become read-only in the browser because React is forcing the value to match the state, but there is no mechanism to update that state.

Previous

react lifecycle

Next

react uncontrolled components

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.