El componente <input>
integrado en el navegador te permite renderizar diferentes tipos de entradas de formularios.
<input />
Referencia
<input>
Para mostrar un input, renderiza el componente <input>
incorporado en el navegador.
<input name="myInput" />
Props
<input>
admite todas las props comunes de los elementos.
Puedes hacer un input controlado pasando una de estas props:
checked
: Booleano. Para un entrada de tipo checkbox o radio button, controla si está seleccionado.value
: String. Para una entrada de texto, controla su texto. (Para un radio button, especifica sus datos de formulario.)
Cuando pases cualquiera de ellos, debes también pasar un manejador onChange
que actualice el valor pasado.
Estas props de <input>
son solamente relevantes para inputs no controlados:
defaultChecked
: Booleano. Especifica el valor inicial para inputstype="checkbox"
ytype="radio"
.defaultValue
: String. Especifica el valor inicial para un input de texto.
Estas props de <input>
son relevantes para ambos inputs controlados y no controlados:
accept
: String. Especifica cuales tipos de archivo son soportados por un inputtype="file"
.alt
: String. Especifica el texto alternativo de una imagen para un inputtype="image"
.capture
: String. Especifica el medio capturado (micrófono, video, o cámara) por un inputtype="file"
.autoComplete
: String. Especifica uno de los posibles comportamientos de autocompletado.autoFocus
: Booleano. Si estrue
, React enfocara al elemento al montarlo.dirname
: String. Especifica el nombre del campo de formulario para la direccionalidad del elemento.disabled
: Booleano. Si estrue
, el input no será interactivo y aparecerá oscurecido.children
:<input>
no acepta hijos.form
: String. Especifica elid
del<form>
al que este input pertenece. Si se omite, es el formulario padre más cercano.formAction
: String. Sobrescribe el<form action>
padre paratype="submit"
ytype="image"
.formEnctype
: String. Sobrescribe el<form enctype>
padre paratype="submit"
ytype="image"
.formMethod
: String. Sobrescribe el<form method>
padre paratype="submit"
ytype="image"
.formNoValidate
: String. Sobrescribe el<form noValidate>
padre paratype="submit"
ytype="image"
.formTarget
: String. Sobrescribe<form target>
padre paratype="submit"
ytype="image"
.height
: String. Especifica la altura de la imagen paratype="image"
.list
: String. Especifica elid
del<datalist>
con las opciones de autocompletado.max
: Número. Especifica el máximo valor de los inputs de tipo numérico y de fecha y hora.maxLength
: Número. Especifica la longitud máxima del texto y otros inputs.min
: Número. Especifica el valor mínimo de los inputs de tipo numérico y de fecha y hora.minLength
: Número. Especifica la longitud mínima de texto y otros inputs.multiple
: Booleano. Especifica si valores múltiples son permitidos para<type="file"
ytype="email"
.name
: String. Especifica el nombre para este input que se envía con el formulario.onChange
: Un manejador de eventos. Requerido para inputs controlados. Se activa inmediatamente cuando el valor del input es cambiado por el usuario (por ejemplo, se activa en cada pulsación de teclas). Se comporta como el eventoinput
del navegador.onChangeCapture
: Una versión deonChange
que se activa en la fase de captura.onInput
: Un manejador de eventos. Se activa inmediatamente cuando el valor es cambiado por el usuario. Por razones históricas, en React es idiomático usaronChange
en su lugar que funciona de forma similar.onInputCapture
: Una version deonInput
que se activa en la fase de captura.onInvalid
: Un manejador de eventos. Se activa si un input falla en la validación cuando se envía un formulario. A diferencia del evento integradoinvalid
, el eventoonInvalid
de React se propaga.onInvalidCapture
: Una versión deonInvalid
que se activa en la fase de captura.onSelect
: Un manejador de evento. Se activa después de selección dentro de los cambios de un<input>
. React hereda el eventoonSelect
para también activarse para selecciones vacías y en ediciones (las cuales pueden afectar la selección).onSelectCapture
: Una versiónonSelect
que se activa en la fase de captura.pattern
: String. Especifica el patrón con el cualvalue
debe coincidir.placeholder
: String. Mostrado en un color atenuado cuando el valor del input esta vació.readOnly
: Booleano. Si estrue
, el usuario no puede editar el input.required
: Booleano. Si estrue
, el valor debe ser proporcionado para poder enviar el formulario.size
: Número. Similar a configurar el ancho, pero la unidad depende del control.src
: String. Especifica la fuente de la imagen para un inputtype="image"
.step
: Un número positivo o un string'any'
. Especifica la distancia entre los valores validos.type
: String. Uno de los tipos de input.width
: String. Especifica el ancho de la imagen para un inputtype="image"
.
Advertencias
- Los Checkboxes necesitan
checked
(odefaultChecked
), novalue
(odefaultValue
). - Si un input de texto recibe una prop
value
de tipo string , será tratado como controlado. - Si un checkbox o un radio button recibe una prop
checked
de tipo booleano, será tratado como controlado. - Un input no puede ser controlado o no controlado al mismo tiempo.
- Un input no puede cambiar entre ser controlado o no durante su ciclo de vida.
- Cada input controlado necesita un manejador de evento
onChange
que sincrónicamente actualice su valor de respaldo.
Uso
Visualización de inputs de diferentes tipos
Para visualizar un input, renderiza un componente <input>
. Por defecto, será un input de tipo texto. Puedes pasar type="checkbox"
para un checkbox, type="radio"
para un radio button, o uno de los otros tipos de inputs.
export default function MyForm() { return ( <> <label> Input de texto: <input name="myInput" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" /> </label> <hr /> <p> Botones radio: <label> <input type="radio" name="myRadio" value="option1" /> Opción 1 </label> <label> <input type="radio" name="myRadio" value="option2" /> Opción 2 </label> <label> <input type="radio" name="myRadio" value="option3" /> Opción 3 </label> </p> </> ); }
Proporcionar una etiqueta para un input
Típicamente, pondrás cada <input>
dentro de una etiqueta <label>
. Esto le dice al navegador que esta etiqueta esta asociada con ese input. Cuando el usuario da click a la etiqueta, el navegador automáticamente enfocará al input. También es esencial para la accesibilidad: un lector de pantalla anunciará la etiqueta cuando el usuario enfoque el input asociado.
Si no puedes anidar un <input>
dentro de un <label>
, asócialos pasando el mismo ID al <input id>
y al <label htmlFor>
. Para evitar conflictos entre múltiples instancias de un componente, genera dicho ID con useId
.
import { useId } from 'react'; export default function Form() { const ageInputId = useId(); return ( <> <label> Tu primer nombre: <input name="firstName" /> </label> <hr /> <label htmlFor={ageInputId}>Tu edad:</label> <input id={ageInputId} name="age" type="number" /> </> ); }
Proporcionar un valor inicial para un input
Puedes opcionalmente especificar el valor inicial para cualquier input. Pásalo como el defaultValue
string para inputs de tipo texto. Checkboxes y radio buttons deben especificar el valor inicial con el defaultChecked
booleano en su lugar.
export default function MyForm() { return ( <> <label> Input de texto: <input name="myInput" defaultValue="Some initial value" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} /> </label> <hr /> <p> Botones radio: <label> <input type="radio" name="myRadio" value="option1" /> Opción 1 </label> <label> <input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Opción 2 </label> <label> <input type="radio" name="myRadio" value="option3" /> Opción 3 </label> </p> </> ); }
Leer los valores de los inputs cuando se envía un formulario
Añade un <form>
que rodee tus inputs con un <button type="submit">
dentro. Llamará tu manejador de evento <form onSubmit>
. Por defecto, el navegador enviará los datos del formulario a el URL actual y refrescará la página. Puedes sobrescribir ese comportamiento llamando e.preventDefault()
. Para leer los datos del formulario, usa new FormData(e.target)
.
export default function MyForm() { function handleSubmit(e) { // Previene que el navegador recargue la página e.preventDefault(); // Lee los datos del formulario const form = e.target; const formData = new FormData(form); // Puedes pasar formData como el cuerpo de la consulta directamente: fetch('/some-api', { method: form.method, body: formData }); // O puedes trabajar con él como un objecto plano: const formJson = Object.fromEntries(formData.entries()); console.log(formJson); } return ( <form method="post" onSubmit={handleSubmit}> <label> Input de texto: <input name="myInput" defaultValue="Some initial value" /> </label> <hr /> <label> Checkbox: <input type="checkbox" name="myCheckbox" defaultChecked={true} /> </label> <hr /> <p> Botones radio: <label><input type="radio" name="myRadio" value="option1" /> Opción 1</label> <label><input type="radio" name="myRadio" value="option2" defaultChecked={true} /> Opción 2</label> <label><input type="radio" name="myRadio" value="option3" /> Opción 3</label> </p> <hr /> <button type="reset">Reiniciar formulario</button> <button type="submit">Enviar formulario</button> </form> ); }
Controlar un input con un estado variable
Un input como <input />
es no controlado. Incluso si pasas un valor inicial como <input defaultValue="Initial text" />
, tu JSX solo especifica el valor inicial. No controla cual debe ser el valor ahora mismo.
Para renderizar un input controlado, pásale la prop value
(o checked
para checkboxes y radios). React forzará al input para que siempre tenga el value
que le pasaste. Típicamente, controlarás un input declarando una variable de estado:
function Form() {
const [firstName, setFirstName] = useState(''); // Declara una variable de estado...
// ...
return (
<input
value={firstName} // ... fuerza al valor del input para que coincida con la variable de estado...
onChange={e => setFirstName(e.target.value)} // ... y actualiza la variable de estado en cada edición!
/>
);
}
Un input controlado te servirá si necesitas un estado de cualquier forma — por ejemplo, para renderizar tu UI en cada edición:
function Form() {
const [firstName, setFirstName] = useState('');
return (
<>
<label>
First name:
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</label>
{firstName !== '' && <p>Tu nombre es {firstName}.</p>}
...
Es también útil si quieres ofrecer múltiples formas de ajustar el estado del input (por ejemplo, al dar click a un botón):
function Form() {
// ...
const [age, setAge] = useState('');
const ageAsNumber = Number(age);
return (
<>
<label>
Edad:
<input
value={age}
onChange={e => setAge(e.target.value)}
type="number"
/>
<button onClick={() => setAge(ageAsNumber + 10)}>
Añade 10 años
</button>
El value
que pases a componentes controlados no debe ser undefined
o null
. Si necesitas que el valor inicial este vacío (así como el campo de firstName
más abajo), inicializa tu variable de estado con un string vacío (''
).
import { useState } from 'react'; export default function Form() { const [firstName, setFirstName] = useState(''); const [age, setAge] = useState('20'); const ageAsNumber = Number(age); return ( <> <label> Primer nombre: <input value={firstName} onChange={e => setFirstName(e.target.value)} /> </label> <label> Edad: <input value={age} onChange={e => setAge(e.target.value)} type="number" /> <button onClick={() => setAge(ageAsNumber + 10)}> Añade 10 años </button> </label> {firstName !== '' && <p>Tu nombre es {firstName}.</p> } {ageAsNumber > 0 && <p>Tu edad es {ageAsNumber}.</p> } </> ); }
Optimizar la re-renderización en cada pulsación del teclado
Cuando usas un input controlado, pones el estado en cada pulsación del teclado. Si el componente que contiene tu estado renderiza de nuevo un árbol grande, este puede volverse lento. Hay varias formas en las que puedes optimizar el rendimiento del re-renderizado.
Por ejemplo, supón que empiezas con un formulario que renderiza de nuevo toda el contenido de la página en cada pulsación del teclado:
function App() {
const [firstName, setFirstName] = useState('');
return (
<>
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
<PageContent />
</>
);
}
Ya que <PageContent />
no depende del estado del input, puedes mover el valor del input dentro de su propio componente:
function App() {
return (
<>
<SignupForm />
<PageContent />
</>
);
}
function SignupForm() {
const [firstName, setFirstName] = useState('');
return (
<form>
<input value={firstName} onChange={e => setFirstName(e.target.value)} />
</form>
);
}
Esto mejora el rendimiento significativamente porque ahora solamente SignupForm
renderiza de nuevo en cada pulsación del teclado.
Si no hay forma de evitar el re-renderizado (por ejemplo, si PageContent
depende del valor de el input de búsqueda), useDeferredValue
te permite mantener el input controlado incluso a la mitad de un re-renderizado grande.
Solución de problemas
Mi input de tipo texto no se actualiza cuando escribo dentro de él
Si renderizas un input con un value
pero sin un onChange
, verás un error en la consola:
// 🔴 Error: input de texto controlado sin un manejador de evento onChange
<input value={something} />
value
a un campo de formulario sin un manejador de evento onChange
. Esto renderiza un campo de solo lectura. Si el campo debe ser mutable usa defaultValue
. En caso contrario, establece onChange
o readOnly
.Como el mensaje de error sugiere, si solo quieres especificar el valor inicial , pasa defaultValue
en su lugar:
// ✅ Bien: input no controlado con un valor inicial
<input defaultValue={something} />
Si quieres controlar este input con una variable de estado, especifica un manejador de evento onChange
:
// ✅ Bien: input controlado con onChange
<input value={something} onChange={e => setSomething(e.target.value)} />
Si el valor es intencionalmente de solo lectura, añade una prop readOnly
para eliminar el error:
// ✅ Bien: input controlado de solo lectura sin un onChange
<input value={something} readOnly={true} />
Mi checkbox no se actualiza cuando le doy click
Si renderizas un checkbox con checked
pero sin onChange
, verás un error en la consola:
// 🔴 Error: checkbox controlado sin un manejador de evento onChange
<input type="checkbox" checked={something} />
checked
a un campo de formulario sin un manejador de evento onChange
. Esto renderizará un campo de solo lectura. Si el campo debe ser mutable usa defaultChecked
. En caso contrario, establece onChange
o readOnly
.Como el error sugiere, si solo quieres especificar el valor inicial, pasa defaultChecked
en su lugar:
// ✅ Bien: checkbox no controlado con un valor inicial
<input type="checkbox" defaultChecked={something} />
Si quieres controlar este checkbox con una variable de estado, especifica un manejador de evento onChange
:
// ✅ Bien: checkbox controlado con onChange
<input type="checkbox" checked={something} onChange={e => setSomething(e.target.checked)} />
Si el checkbox es intencionalmente de solo lectura, añade una prop readOnly
para eliminar el error:
// ✅ Bien: input controlado de solo lectura sin un onChange
<input type="checkbox" checked={something} readOnly={true} />
El caret de mi input salta al principio de cada pulsación del teclado
Si controlas un input, debes actualizar su variable de estado con el valor del input desde el DOM durante onChange
.
No puedes actualizarlo a algo distinto a e.target.value
(o e.target.checked
para checkboxes):
function handleChange(e) {
// 🔴 Error: actualizando un input a algo distinto a e.target.value
setFirstName(e.target.value.toUpperCase());
}
También no puedes actualizarlo asincrónicamente:
function handleChange(e) {
// 🔴 Error: actualizando un input asincrónicamente
setTimeout(() => {
setFirstName(e.target.value);
}, 100);
}
Para arreglar tu código, actualízalo sincrónicamente a e.target.value
:
function handleChange(e) {
// ✅ Actualizando un input controlado a e.target.value sincrónicamente
setFirstName(e.target.value);
}
Si esto no repara el problema, es posible que el input sea removido y re-agregado al DOM en cada pulsación de tecla. Esto puede ocurrir si tú estás accidentalmente reseteando el estado en cada re-renderización, por ejemplo, si el input o uno de sus padres siempre recibe un atributo key
diferente, o si tú anidas definiciones de funciones de componentes (lo cual no es soportado y causa que el componente «interno» siempre sea considerado un árbol diferente).
Estoy teniendo un error: «Un componente esta cambiando un input no controlado para ser controlado»
Si proporcionas un value
al componente, debe seguir siendo un string durante de su ciclo de vida.
No puedes pasar value={undefined}
primero y luego pasar value="some string"
porque React no sabrá si quieres que el componente sea controlado o no. Un componente controlado debería siempre recibir un value
de tipo string, no un null
o undefined
.
Si tu value
viene desde una API o de una variable de estado, puede ser inicializado en null
o undefined
. En ese caso, o bien establécelo en un string vacío (''
) inicialmente, o pasa value={someValue ?? ''}
para asegurar que value
es un string.
Similarmente, si pasas checked
a un checkbox, asegúrate de que siempre sea un booleano.