React throws this warning when both value and defaultValue props are specified on a form element. This happens when developers accidentally mix controlled and uncontrolled component patterns, which creates ambiguity about who manages the input state.
This warning occurs when you use both the `value` and `defaultValue` props on a React form element (input, textarea, or select). React enforces a clear distinction between controlled and uncontrolled components, and using both props simultaneously violates this principle. In a **controlled component**, React state manages the input value through the `value` prop and `onChange` handler. The component's state is the single source of truth. In an **uncontrolled component**, the DOM itself manages the input value, and you use `defaultValue` to set the initial value. You cannot mix both approaches on the same element. This is a development-only warning that React displays to help you catch component design issues early. While your app may still function, the behavior becomes unpredictable as React won't know whether to treat the input as controlled or uncontrolled.
Check your browser console for the full warning message, which will indicate the component and input type causing the issue.
Look for any <input>, <textarea>, or <select> elements that have both value and defaultValue props set.
Choose controlled components (recommended for most cases):
- When you need form validation on each keystroke
- When input values depend on each other
- When you need to conditionally enable/disable submit buttons
- When building complex forms with state management
Choose uncontrolled components when:
- Building simple forms without instant validation
- Integrating with non-React libraries
- Performance optimization for very large forms
- You only need the value on form submission
Convert to a fully controlled component by removing defaultValue and managing the value through React state:
import { useState } from 'react';
function MyForm() {
// Initialize state with the default value
const [inputValue, setInputValue] = useState('initial value');
return (
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
);
}Key points:
- Always initialize state with a defined value (not undefined)
- Use an empty string '' if there's no initial value
- Provide an onChange handler to update the state
Convert to a fully uncontrolled component by removing value and using defaultValue with a ref:
import { useRef } from 'react';
function MyForm() {
const inputRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
// Access the current value from the DOM
console.log(inputRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
defaultValue="initial value"
ref={inputRef}
/>
<button type="submit">Submit</button>
</form>
);
}Key points:
- Use defaultValue to set the initial value
- Access the current value via ref when needed (typically on submit)
- No onChange handler needed unless you need side effects
If you're spreading props onto an input, ensure the object doesn't contain both value and defaultValue:
// Problem: props object contains both
function Input(props) {
return <input {...props} />; // May contain both value and defaultValue
}
// Solution 1: Destructure and only use one
function Input({ defaultValue, ...props }) {
return <input {...props} />; // Explicitly exclude defaultValue
}
// Solution 2: Use explicit props
function Input({ value, onChange, type, placeholder }) {
return <input type={type} value={value} onChange={onChange} placeholder={placeholder} />;
}A common variant of this error occurs when value switches from undefined to a defined value (or vice versa), making React think you're switching from uncontrolled to controlled:
// Problem: value might be undefined initially
const [name, setName] = useState(user?.name); // undefined if user is null
return <input value={name} onChange={e => setName(e.target.value)} />;
// Solution: Always provide a defined value
const [name, setName] = useState(user?.name || '');
// Or use nullish coalescing
const [name, setName] = useState(user?.name ?? '');
return <input value={name} onChange={e => setName(e.target.value)} />;Form Libraries and This Warning:
Popular form libraries like React Hook Form and Formik handle controlled/uncontrolled patterns internally. If you're using these libraries and still see this warning, check:
- Whether you're manually setting both value and defaultValue on registered inputs
- If library docs recommend using their custom input components
- Whether you need to use their specific registration methods
TypeScript Type Safety:
You can create TypeScript types to prevent this error at compile time:
// Controlled input props
type ControlledInputProps = {
value: string;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
defaultValue?: never; // Explicitly disallow
};
// Uncontrolled input props
type UncontrolledInputProps = {
defaultValue?: string;
value?: never; // Explicitly disallow
onChange?: never;
};
type InputProps = ControlledInputProps | UncontrolledInputProps;Performance Considerations:
Controlled components re-render on every keystroke, which is fine for most forms but can be problematic for:
- Very large forms (50+ fields)
- Rich text editors
- Real-time validation with expensive operations
In these cases, consider uncontrolled components with refs or debounced validation.
React DevTools:
Use React DevTools to inspect component props and verify whether an input is controlled or uncontrolled. Controlled inputs will show the value prop updating on every keystroke in the devtools inspector.
Migration Strategy for Large Codebases:
If refactoring a large codebase with this warning:
1. Use ESLint rules to detect the pattern: react/no-uncontrolled-state
2. Add TODO comments to inputs that need refactoring
3. Prioritize critical user-facing forms first
4. Create wrapper components that enforce consistent patterns
5. Document your team's chosen pattern in a style guide
React.FC expects children prop to be defined
React.FC no longer includes implicit children prop
Warning: You provided a `selected` prop to a form field without an `onChange` handler
You provided a 'selected' prop without an onChange handler
Failed to load source map from suspense chunk
How to fix "Failed to load source map from suspense chunk" in React
Prop spreading could cause security issues
Prop spreading could cause security issues
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency