Thebuilt-in browser<input>
component lets you render different kinds of form inputs.
<input/>
Reference
<input>
To display an input, render thebuilt-in browser<input>
component.
<inputname="myInput"/>
Props
<input>
supports allcommon element props.
formAction
: A string or function. Overrides the parent<form action>
fortype="submit"
andtype="image"
. When a URL is passed toaction
the form will behave like a standard HTML form. When a function is passed toformAction
the function will handle the form submission. See<form action>
.
You canmake an input controlled by passing one of these props:
checked
: A boolean. For a checkbox input or a radio button, controls whether it is selected.value
: A string. For a text input, controls its text. (For a radio button, specifies its form data.)
When you pass either of them, you must also pass anonChange
handler that updates the passed value.
These<input>
props are only relevant for uncontrolled inputs:
defaultChecked
: A boolean. Specifiesthe initial value fortype="checkbox"
andtype="radio"
inputs.defaultValue
: A string. Specifiesthe initial value for a text input.
These<input>
props are relevant both for uncontrolled and controlled inputs:
accept
: A string. Specifies which filetypes are accepted by atype="file"
input.alt
: A string. Specifies the alternative image text for atype="image"
input.capture
: A string. Specifies the media (microphone, video, or camera) captured by atype="file"
input.autoComplete
: A string. Specifies one of the possibleautocomplete behaviors.autoFocus
: A boolean. Iftrue
, React will focus the element on mount.dirname
: A string. Specifies the form field name for the element’s directionality.disabled
: A boolean. Iftrue
, the input will not be interactive and will appear dimmed.children
:<input>
does not accept children.form
: A string. Specifies theid
of the<form>
this input belongs to. If omitted, it’s the closest parent form.formAction
: A string. Overrides the parent<form action>
fortype="submit"
andtype="image"
.formEnctype
: A string. Overrides the parent<form enctype>
fortype="submit"
andtype="image"
.formMethod
: A string. Overrides the parent<form method>
fortype="submit"
andtype="image"
.formNoValidate
: A string. Overrides the parent<form noValidate>
fortype="submit"
andtype="image"
.formTarget
: A string. Overrides the parent<form target>
fortype="submit"
andtype="image"
.height
: A string. Specifies the image height fortype="image"
.list
: A string. Specifies theid
of the<datalist>
with the autocomplete options.max
: A number. Specifies the maximum value of numerical and datetime inputs.maxLength
: A number. Specifies the maximum length of text and other inputs.min
: A number. Specifies the minimum value of numerical and datetime inputs.minLength
: A number. Specifies the minimum length of text and other inputs.multiple
: A boolean. Specifies whether multiple values are allowed for<type="file"
andtype="email"
.name
: A string. Specifies the name for this input that’ssubmitted with the form.onChange
: AnEvent
handler function. Required forcontrolled inputs. Fires immediately when the input’s value is changed by the user (for example, it fires on every keystroke). Behaves like the browserinput
event.onChangeCapture
: A version ofonChange
that fires in thecapture phase.onInput
: AnEvent
handler function. Fires immediately when the value is changed by the user. For historical reasons, in React it is idiomatic to useonChange
instead which works similarly.onInputCapture
: A version ofonInput
that fires in thecapture phase.onInvalid
: AnEvent
handler function. Fires if an input fails validation on form submit. Unlike the built-ininvalid
event, the ReactonInvalid
event bubbles.onInvalidCapture
: A version ofonInvalid
that fires in thecapture phase.onSelect
: AnEvent
handler function. Fires after the selection inside the<input>
changes. React extends theonSelect
event to also fire for empty selection and on edits (which may affect the selection).onSelectCapture
: A version ofonSelect
that fires in thecapture phase.pattern
: A string. Specifies the pattern that thevalue
must match.placeholder
: A string. Displayed in a dimmed color when the input value is empty.readOnly
: A boolean. Iftrue
, the input is not editable by the user.required
: A boolean. Iftrue
, the value must be provided for the form to submit.size
: A number. Similar to setting width, but the unit depends on the control.src
: A string. Specifies the image source for atype="image"
input.step
: A positive number or an'any'
string. Specifies the distance between valid values.type
: A string. One of theinput types.width
: A string. Specifies the image width for atype="image"
input.
Caveats
- Checkboxes need
checked
(ordefaultChecked
), notvalue
(ordefaultValue
). - If a text input receives a string
value
prop, it will betreated as controlled. - If a checkbox or a radio button receives a boolean
checked
prop, it will betreated as controlled. - An input can’t be both controlled and uncontrolled at the same time.
- An input cannot switch between being controlled or uncontrolled over its lifetime.
- Every controlled input needs an
onChange
event handler that synchronously updates its backing value.
Usage
Displaying inputs of different types
To display an input, render an<input>
component. By default, it will be a text input. You can passtype="checkbox"
for a checkbox,type="radio"
for a radio button,or one of the other input types.
exportdefaultfunctionMyForm(){return(<><label> Text input:<inputname="myInput"/></label><hr/><label> Checkbox:<inputtype="checkbox"name="myCheckbox"/></label><hr/><p> Radio buttons:<label><inputtype="radio"name="myRadio"value="option1"/> Option 1</label><label><inputtype="radio"name="myRadio"value="option2"/> Option 2</label><label><inputtype="radio"name="myRadio"value="option3"/> Option 3</label></p></>);}
Providing a label for an input
Typically, you will place every<input>
inside a<label>
tag. This tells the browser that this label is associated with that input. When the user clicks the label, the browser will automatically focus the input. It’s also essential for accessibility: a screen reader will announce the label caption when the user focuses the associated input.
If you can’t nest<input>
into a<label>
, associate them by passing the same ID to<input id>
and<label htmlFor>
. To avoid conflicts between multiple instances of one component, generate such an ID withuseId
.
import{useId}from'react';exportdefaultfunctionForm(){constageInputId =useId();return(<><label> Your first name:<inputname="firstName"/></label><hr/><labelhtmlFor={ageInputId}>Your age:</label><inputid={ageInputId}name="age"type="number"/></>);}
Providing an initial value for an input
You can optionally specify the initial value for any input. Pass it as thedefaultValue
string for text inputs. Checkboxes and radio buttons should specify the initial value with thedefaultChecked
boolean instead.
exportdefaultfunctionMyForm(){return(<><label> Text input:<inputname="myInput"defaultValue="Some initial value"/></label><hr/><label> Checkbox:<inputtype="checkbox"name="myCheckbox"defaultChecked={true}/></label><hr/><p> Radio buttons:<label><inputtype="radio"name="myRadio"value="option1"/> Option 1</label><label><inputtype="radio"name="myRadio"value="option2"defaultChecked={true}/> Option 2</label><label><inputtype="radio"name="myRadio"value="option3"/> Option 3</label></p></>);}
Reading the input values when submitting a form
Add a<form>
around your inputs with a<button type="submit">
inside. It will call your<form onSubmit>
event handler. By default, the browser will send the form data to the current URL and refresh the page. You can override that behavior by callinge.preventDefault()
. Read the form data withnew FormData(e.target)
.
exportdefaultfunctionMyForm(){functionhandleSubmit(e){// Prevent the browser from reloading the pagee.preventDefault();// Read the form dataconstform =e.target;constformData =newFormData(form);// You can pass formData as a fetch body directly:fetch('/some-api',{method:form.method,body:formData});// Or you can work with it as a plain object:constformJson =Object.fromEntries(formData.entries());console.log(formJson);}return(<formmethod="post"onSubmit={handleSubmit}><label> Text input:<inputname="myInput"defaultValue="Some initial value"/></label><hr/><label> Checkbox:<inputtype="checkbox"name="myCheckbox"defaultChecked={true}/></label><hr/><p> Radio buttons:<label><inputtype="radio"name="myRadio"value="option1"/> Option 1</label><label><inputtype="radio"name="myRadio"value="option2"defaultChecked={true}/> Option 2</label><label><inputtype="radio"name="myRadio"value="option3"/> Option 3</label></p><hr/><buttontype="reset">Reset form</button><buttontype="submit">Submit form</button></form>);}
Note
Give aname
to every<input>
, for example<input name="firstName" defaultValue="Taylor" />
. Thename
you specified will be used as a key in the form data, for example{ firstName: "Taylor" }
.
Pitfall
By default, a<button>
inside a<form>
without atype
attribute will submit it. This can be surprising! If you have your own customButton
React component, consider using<button type="button">
instead of<button>
(with no type). Then, to be explicit, use<button type="submit">
for buttons thatare supposed to submit the form.
Controlling an input with a state variable
An input like<input />
isuncontrolled. Even if youpass an initial value like<input defaultValue="Initial text" />
, your JSX only specifies the initial value. It does not control what the value should be right now.
To render acontrolled input, pass thevalue
prop to it (orchecked
for checkboxes and radios). React will force the input to always have thevalue
you passed. Usually, you would do this by declaring astate variable:
functionForm(){
const[firstName,setFirstName] =useState('');// Declare a state variable...
// ...
return(
<input
value={firstName}// ...force the input's value to match the state variable...
onChange={e=>setFirstName(e.target.value)}// ... and update the state variable on any edits!
/>
);
}
A controlled input makes sense if you needed state anyway—for example, to re-render your UI on every edit:
functionForm(){
const[firstName,setFirstName] =useState('');
return(
<>
<label>
First name:
<inputvalue={firstName}onChange={e=>setFirstName(e.target.value)}/>
</label>
{firstName !=='' &&<p>Your name is{firstName}.</p>}
...
It’s also useful if you want to offer multiple ways to adjust the input state (for example, by clicking a button):
functionForm(){
// ...
const[age,setAge] =useState('');
constageAsNumber =Number(age);
return(
<>
<label>
Age:
<input
value={age}
onChange={e=>setAge(e.target.value)}
type="number"
/>
<buttononClick={()=>setAge(ageAsNumber +10)}>
Add 10 years
</button>
Thevalue
you pass to controlled components should not beundefined
ornull
. If you need the initial value to be empty (such as with thefirstName
field below), initialize your state variable to an empty string (''
).
import{useState}from'react';exportdefaultfunctionForm(){const[firstName,setFirstName] =useState('');const[age,setAge] =useState('20');constageAsNumber =Number(age);return(<><label> First name:<inputvalue={firstName}onChange={e=>setFirstName(e.target.value)}/></label><label> Age:<inputvalue={age}onChange={e=>setAge(e.target.value)}type="number"/><buttononClick={()=>setAge(ageAsNumber +10)}> Add 10 years</button></label>{firstName !=='' &&<p>Your name is{firstName}.</p>}{ageAsNumber >0 &&<p>Your age is{ageAsNumber}.</p>}</>);}
Pitfall
If you passvalue
withoutonChange
, it will be impossible to type into the input. When you control an input by passing somevalue
to it, youforce it to always have the value you passed. So if you pass a state variable as avalue
but forget to update that state variable synchronously during theonChange
event handler, React will revert the input after every keystroke back to thevalue
that you specified.
Optimizing re-rendering on every keystroke
When you use a controlled input, you set the state on every keystroke. If the component containing your state re-renders a large tree, this can get slow. There’s a few ways you can optimize re-rendering performance.
For example, suppose you start with a form that re-renders all page content on every keystroke:
functionApp(){
const[firstName,setFirstName] =useState('');
return(
<>
<form>
<inputvalue={firstName}onChange={e=>setFirstName(e.target.value)}/>
</form>
<PageContent/>
</>
);
}
Since<PageContent />
doesn’t rely on the input state, you can move the input state into its own component:
functionApp(){
return(
<>
<SignupForm/>
<PageContent/>
</>
);
}
functionSignupForm(){
const[firstName,setFirstName] =useState('');
return(
<form>
<inputvalue={firstName}onChange={e=>setFirstName(e.target.value)}/>
</form>
);
}
This significantly improves performance because now onlySignupForm
re-renders on every keystroke.
If there is no way to avoid re-rendering (for example, ifPageContent
depends on the search input’s value),useDeferredValue
lets you keep the controlled input responsive even in the middle of a large re-render.
Troubleshooting
My text input doesn’t update when I type into it
If you render an input withvalue
but noonChange
, you will see an error in the console:
// 🔴 Bug: controlled text input with no onChange handler
<inputvalue={something}/>
value
prop to a form field without anonChange
handler. This will render a read-only field. If the field should be mutable usedefaultValue
. Otherwise, set eitheronChange
orreadOnly
.As the error message suggests, if you only wanted tospecify theinitial value, passdefaultValue
instead:
// ✅ Good: uncontrolled input with an initial value
<inputdefaultValue={something}/>
If you wantto control this input with a state variable, specify anonChange
handler:
// ✅ Good: controlled input with onChange
<inputvalue={something}onChange={e=>setSomething(e.target.value)}/>
If the value is intentionally read-only, add areadOnly
prop to suppress the error:
// ✅ Good: readonly controlled input without on change
<inputvalue={something}readOnly={true}/>
My checkbox doesn’t update when I click on it
If you render a checkbox withchecked
but noonChange
, you will see an error in the console:
// 🔴 Bug: controlled checkbox with no onChange handler
<inputtype="checkbox"checked={something}/>
checked
prop to a form field without anonChange
handler. This will render a read-only field. If the field should be mutable usedefaultChecked
. Otherwise, set eitheronChange
orreadOnly
.As the error message suggests, if you only wanted tospecify theinitial value, passdefaultChecked
instead:
// ✅ Good: uncontrolled checkbox with an initial value
<inputtype="checkbox"defaultChecked={something}/>
If you wantto control this checkbox with a state variable, specify anonChange
handler:
// ✅ Good: controlled checkbox with onChange
<inputtype="checkbox"checked={something}onChange={e=>setSomething(e.target.checked)}/>
Pitfall
You need to reade.target.checked
rather thane.target.value
for checkboxes.
If the checkbox is intentionally read-only, add areadOnly
prop to suppress the error:
// ✅ Good: readonly controlled input without on change
<inputtype="checkbox"checked={something}readOnly={true}/>
My input caret jumps to the beginning on every keystroke
If youcontrol an input, you must update its state variable to the input’s value from the DOM duringonChange
.
You can’t update it to something other thane.target.value
(ore.target.checked
for checkboxes):
functionhandleChange(e){
// 🔴 Bug: updating an input to something other than e.target.value
setFirstName(e.target.value.toUpperCase());
}
You also can’t update it asynchronously:
functionhandleChange(e){
// 🔴 Bug: updating an input asynchronously
setTimeout(()=>{
setFirstName(e.target.value);
},100);
}
To fix your code, update it synchronously toe.target.value
:
functionhandleChange(e){
// ✅ Updating a controlled input to e.target.value synchronously
setFirstName(e.target.value);
}
If this doesn’t fix the problem, it’s possible that the input gets removed and re-added from the DOM on every keystroke. This can happen if you’re accidentallyresetting state on every re-render, for example if the input or one of its parents always receives a differentkey
attribute, or if you nest component function definitions (which is not supported and causes the “inner” component to always be considered a different tree).
I’m getting an error: “A component is changing an uncontrolled input to be controlled”
If you provide avalue
to the component, it must remain a string throughout its lifetime.
You cannot passvalue={undefined}
first and later passvalue="some string"
because React won’t know whether you want the component to be uncontrolled or controlled. A controlled component should always receive a stringvalue
, notnull
orundefined
.
If yourvalue
is coming from an API or a state variable, it might be initialized tonull
orundefined
. In that case, either set it to an empty string (''
) initially, or passvalue={someValue ?? ''}
to ensurevalue
is a string.
Similarly, if you passchecked
to a checkbox, ensure it’s always a boolean.