<input>
Renders a browser form control that React can drive from state or leave to the DOM.
<input name="myInput" />Parameters
| Parameter | Type | Description |
|---|---|---|
$valueoptional | string | For a text input, controls its text. For a radio button, specifies its form data. Passing it makes the input controlled and requires an onChange handler. |
$checkedoptional | boolean | For a checkbox or radio button, controls whether it is selected. Passing it makes the input controlled and requires an onChange handler. |
$defaultValueoptional | string | Specifies the initial value for a text input in an uncontrolled input. |
$defaultCheckedoptional | boolean | Specifies the initial value for type="checkbox" and type="radio" in an uncontrolled input. |
$onChangeoptional | (event: Event) => void | Required for controlled inputs. Fires immediately when the value is changed by the user — on every keystroke. Behaves like the browser input event, not the native change event. |
$typeoptional | string= 'text' | One of the HTML input types: text, checkbox, radio, file, number, date, submit, image and so on. |
$nameoptional | string | The name this input is submitted under in the form data. Fields without a name never appear in FormData. |
$formActionoptional | string | ((formData: FormData) => void | Promise<void>) | Overrides the parent <form action> for type="submit" and type="image". A URL behaves like a standard HTML form; a function handles the submission. |
$disabledoptional | boolean= false | If true, the input will not be interactive and will appear dimmed. |
$readOnlyoptional | boolean= false | If true, the input is not editable by the user but still submits its value. |
$requiredoptional | boolean= false | If true, the value must be provided for the form to submit. |
$...propsoptional | HTMLInputElement props | <input> supports all common element props plus accept, alt, autoComplete, autoFocus, capture, dirname, form, formEnctype, formMethod, formNoValidate, formTarget, height, list, max, maxLength, min, minLength, multiple, pattern, placeholder, size, src, step, width and the onInput, onInvalid and onSelect handlers. It does not accept children. |
Return value
ReactElementRenders a browser <input> element. Its value is owned by React when value or checked is passed, and by the DOM otherwise.
Errors
React logs an error when an input switches between controlled and uncontrolled during its lifetime, or when a value prop is passed without an onChange handler and without readOnly.
Changelog
- PHP 19.0.0formAction accepts a function, letting a submit input override the parent form's action.
- PHP 19.0.0ref is an ordinary prop on function components, so wrapper components around <input> no longer need forwardRef.
<input> is the built-in browser control, and the single decision that shapes every bug around it is who owns the value. Pass value (or checked for checkboxes and radios) and React owns it: the DOM will only ever display what state says, so an onChange that writes that state back is mandatory. Pass defaultValue (or defaultChecked) and the DOM owns it; you read it later through a ref or from the form's FormData.
Choosing between them
Control the input when something else on screen depends on the current text — a live preview, a disabled submit button, a filter. Leave it uncontrolled for ordinary fields you only read once, on submit; it is less code and fewer renders.
What trips people up
- Checkboxes and radios use
checked/defaultChecked, nevervalue. Readevent.target.checked, notevent.target.value. value={undefined}orvalue={null}makes an input uncontrolled, producing the famous "changing an uncontrolled input to be controlled" warning. Initialise state to''.- React's
onChangefires on every keystroke, unlike the nativechangeevent that fires on blur. type="file"can only ever be uncontrolled.
Example
When to use it
- Filter a list as the user types by controlling the search field with state
- Collect a signup form's fields uncontrolled and read them all from FormData on submit
- Toggle a settings checkbox and immediately enable or disable dependent controls
Frequently asked questions
Why does React warn that a component is changing an uncontrolled input to be controlled?
The input's value prop was undefined or null on the first render and became a string later. Initialise the state with an empty string — useState('') rather than useState() or useState(null) — or pass value={data.name ?? ''} when the value comes from data that arrives asynchronously.
Why can't I type in my input?
You passed a value prop without an onChange handler that writes the new value back to state, so React re-renders the field with the same old value after every keystroke. Add onChange={e => setValue(e.target.value)}, or use defaultValue if the field is meant to be uncontrolled, or add readOnly if it is genuinely fixed.
How do I get the value of an input on submit?
Either read it from state if the input is controlled, or build a FormData from the form element — new FormData(event.currentTarget) — and call data.get('fieldName'). With a function form action, React hands you that FormData directly. Every field you want to read needs a name prop.
More examples
Reading every field at once with FormData
Submitting renders `street=12 Baker St, city=London, gift=on, note=`. Three details are worth noting: an unchecked checkbox is absent from FormData entirely rather than present as false, a checked one contributes the string "on" unless you give it a value prop, and an empty text field still appears with an empty string. No state is needed for the fields themselves — only for showing the result.
import { useState } from "react";
export default function ShippingForm() {
const [summary, setSummary] = useState("not submitted");
function handleSubmit(e) {
e.preventDefault();
const data = new FormData(e.currentTarget);
const entries = [...data.entries()]
.map(([key, value]) => `${key}=${value}`)
.join(", ");
setSummary(entries);
}
return (
<form onSubmit={handleSubmit}>
<input name="street" defaultValue="12 Baker St" />
<input name="city" defaultValue="London" />
<input type="checkbox" name="gift" defaultChecked />
<input name="note" />
<button type="submit">Submit</button>
<p>{summary}</p>
</form>
);
}A file input is always uncontrolled
Picking two images renders their names as a sorted list. A file input cannot be controlled — the browser refuses to let script set its value to anything but the empty string, for security — so there is no value prop here at all. Clearing therefore means reaching for the DOM node through a ref and assigning `""`, which is the one legal assignment, then resetting the state that mirrors it.
import { useRef, useState } from "react";
export default function FilePicker() {
const inputRef = useRef(null);
const [names, setNames] = useState([]);
function handleChange(e) {
const picked = Array.from(e.target.files).map((file) => file.name);
setNames(picked.sort());
}
return (
<div>
<input
type="file"
ref={inputRef}
multiple
accept=".png,.jpg"
onChange={handleChange}
/>
<button onClick={() => { inputRef.current.value = ""; setNames([]); }}>
Clear
</button>
<ul>
{names.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
</div>
);
}A number field that survives an empty box
Typing 4 shows `Total: 20 credits`; clearing the box shows `Total: 0 credits` and leaves the field empty rather than snapping to 0. Storing Number(e.target.value) directly is the common mistake: an empty box parses to NaN, and coercing NaN back to a value prop makes React re-render the field as the string "NaN" that the user cannot delete. Keeping the raw string in state and deriving the number solves it.
import { useState } from "react";
export default function QuantityField() {
// Keep the raw string in state, not a number.
const [raw, setRaw] = useState("3");
const quantity = raw === "" ? 0 : Number(raw);
return (
<p>
<label>
Quantity:{" "}
<input
type="number"
min={0}
max={99}
step={1}
value={raw}
onChange={(e) => setRaw(e.target.value)}
/>
</label>{" "}
Total: {quantity * 5} credits
</p>
);
}
Discussion