<textarea>
El componente <textarea>
que viene integrado en el navegador te permite renderizar un input de texto multilínea.
<textarea />
Referencia
<textarea>
Para mostrar un text area, renderiza el componente <textarea>
que viene integrado en el navegador.
<textarea name="contenidoPost" />
Props
<textarea>
soporta todas las props comunes de los elementos.
Puedes hacer un text area controlado pasando la prop value
:
value
: Un string. Controla el texto dentro del text area.
Cuando pasas value
, también debes pasar un manejador onChange
que actualice el valor proporcionado.
En cambio, si tu <textarea>
no es controlado, puedes pasar la prop defaultValue
:
defaultValue
: Un string. Especifica el valor inicial para un text area.
Estas props de <textarea>
son relevantes tanto para text areas controlados como no controlados:
autoComplete
:'on'
u'off'
. Especifica el comportamiento del autocompletado.autoFocus
: Un booleano. Si estrue
, React enfocará el elemento al montarlo.children
:<textarea>
no acepta hijos. Para establecer el valor inicial, usadefaultValue
.cols
: Un número. Especifica la anchura por defecto en promedio de anchura de carácter. El valor por defecto es20
.disabled
: Un booleano. Si estrue
, el input no será interactivo y aparecerá atenuado.form
: Un string. Especifica elid
del<form>
al que este input pertenece. Si es omitido, es el formulario padre mas cercano.maxLength
: Un número. Especifica la longitud máxima del texto.minLength
: Un número. Especifica la longitud mínima del texto.name
: Un string. Especifica el nombre para este input que es enviado con el formulario.onChange
: Una función manejadora de eventos. Requerida para text areas controlados. Es ejecutada inmediatamente cuando el valor del input es modificado por el usuario (por ejemplo, es ejecutada con cada pulsación de tecla). Se comporta como el eventoinput
del navegador.onChangeCapture
: Una versión deonChange
que es ejecutada en la fase de captura.onInput
: Una función manejadora de eventos. Es ejecutada inmediatamente cuando el valor es cambiado por el usuario. Por razones históricas, en React es idiomático usaronChange
en su lugar, el cual funciona de manera similar.onInputCapture
: Una versión deonInput
que es ejecutada en la fase de captura.onInvalid
: Una función manejadora de eventos. Es ejecutada si la validación de un input fracasa al enviar el formulario. A diferencia del eventoinvalid
que viene integrado, el eventoonInvalid
de React se propaga.onInvalidCapture
: Una versión deonInvalid
que es ejecutado en la fase de captura.onSelect
: Una función manejadora de eventos. Es ejecutada después de que la selección dentro de<textarea>
cambia. React extiende el eventoonSelect
para que también sea ejecutado para selecciones vacías y en ediciones (las cuales puede afectar la selección).onSelectCapture
: Una versión deonSelect
que es ejecutada en la fase de captura.placeholder
: Un string. Mostrado en un color atenuado cuando el valor del text area está vacío.readOnly
: Un booleano. Si estrue
, el text area no puede ser editado por el usuario.required
: Un booleano. Si estrue
, el valor debe ser proporcionado para que el formulario sea enviado.rows
: Un número. Especifica la altura por defecto en promedio de altura de carácter. El valor por defecto es2
.wrap
:'hard'
,'soft'
, u'off'
. Especifica la manera en que el texto debe ser envuelto al enviar un form.
Advertencias
- No es permitido pasar un hijo como
<textarea>algo</textarea>
. UsadefaultValue
para el contenido inicial. - Si un text area recibe una prop
value
string, este será tratado como controlado. - Un text area no puede ser controlado y no controlado a la vez.
- Un text area no puede alternar entre ser controlado o no controlado a lo largo de su vida.
- Todo text area controlado necesita un manejador de evento
onChange
que actualice su valor de manera síncrona.
Uso
Mostrar un text area
Renderiza <textarea>
para mostrar un text area. Puedes especificar su tamaño por defecto con los atributos rows
y cols
, pero por defecto el usuario será capaz de modificar su tamaño. Para deshabilitar la modificación de tamaño, puedes especificar resize: none
en el CSS.
export default function NuevoPost() { return ( <label> Escribe tu post: <textarea name="contenidoPost" rows={4} cols={40} /> </label> ); }
Proporcionar un label para un text area
Típicamente, colocarás todos los <textarea>
dentro de una etiqueta <label>
. Esto le indica al navegador que este label está asociado con ese text area. Cuando el usuario haca click en el label, el navegador enfocará el text area. Esto también es esencial para accesibilidad: un lector de pantallas anunciará el texto del label cuando el usuario enfoque el text area.
Si no puedes anidar el <textarea>
dentro de un <label>
, asociales pasando el mismo identificador a <textarea id>
y <label htmlFor>
. Para evitar conflictos entre instancias de un componente, genera un identificador con useId
.
import { useId } from 'react'; export default function Formulario() { const postTextAreaId = useId(); return ( <> <label htmlFor={postTextAreaId}> Escribe tu post: </label> <textarea id={postTextAreaId} name="contenidoPost" rows={4} cols={40} /> </> ); }
Proporcionar un valor inicial para un text area
Opcionalmente puedes especificar el valor inicial de un text area. Pásalo a través de la prop defaultValue
.
export default function EditarPost() { return ( <label> Edita tu post: <textarea name="contenidoPost" defaultValue="¡Disfruté el paseo en bicicleta de ayer!" rows={4} cols={40} /> </label> ); }
Leer el valor de text area al enviar un formulario
Agrega un <form>
alrededor de tu text area con un <button type="submit">
dentro. Este llamará a tu manejador de evento <form onSubmit>
. Por defecto, el navegador enviara los datos del formulario a el URL actual y actualizará la página. Puedes sobrescribir ese comportamiento llamando e.preventDefault()
. Para leer los datos del formulario, usa new FormData(e.target)
.
export default function EditarPost() { function handleSubmit(e) { // Evita que el navegador actualice la página e.preventDefault(); // Lee los datos del formulario const form = e.target; const formData = new FormData(form); // Puedes pasar formData directamente como body fetch('/some-api', { method: form.method, body: formData }); // O puedes trabajarlo como un objeto plano: const formJson = Object.fromEntries(formData.entries()); console.log(formJson); } return ( <form method="post" onSubmit={handleSubmit}> <label> Título del post: <input name="tituloPost" defaultValue="Paseo en bicicleta" /> </label> <label> Edita tu post: <textarea name="contenidoPost" defaultValue="¡Disfruté el paseo en bicicleta de ayer!" rows={4} cols={40} /> </label> <hr /> <button type="reset">Reiniciar cambios</button> <button type="submit">Guardar post</button> </form> ); }
Controlar un text area con una variable de estado
Un text area como <textarea />
es no controlado. Incluso si pasas un valor inicial como <textarea defaultValue="Texto inicial" />
, tu JSX solo especifica el valor inicial, no el valor actual.
Para renderizar un text area controlado, pásale la prop value
. React forzará al text area a siempre tener value
que pasaste. Normalmente, controlarás un text area declarando una variable de estado:
function NuevoPost() {
const [contenidoPost, asignaContenidoPost] = useState(''); // Declara una variable de estado...
// ...
return (
<textarea
value={contenidoPost} // ...fuerza al valor del input a que coincida con la variable de estado...
onChange={e => asignaContenidoPost(e.target.value)} // ... ¡y actualiza la variable de estado con cada cambio!
/>
);
}
Esto es útil si quieres re-renderizar alguna parte de la IU cada vez que una tecla sea pulsada.
import { useState } from 'react'; import MarkdownPreview from './MarkdownPreview.js'; export default function EditorMarkdown() { const [contenidoPost, asignaContenidoPost] = useState('_Hola,_ **Markdown**!'); return ( <> <label> Inserta markdown: <textarea value={contenidoPost} onChange={e => asignaContenidoPost(e.target.value)} /> </label> <hr /> <MarkdownPreview markdown={contenidoPost} /> </> ); }
Solución de problemas
Mi text area no se actualiza cuando escribo en él
Si renderizas un text area con value
pero sin onChange
, verás un error en la consola:
// 🔴 Error: text area controlado sin manejador onChange
<textarea value={algo} />
value
prop to a form field without an onChange
handler. This will render a read-only field. If the field should be mutable use defaultValue
. Otherwise, set either onChange
or readOnly
.Como sugiere el mensaje de error, si solo quisiste especificar el valor inicial, solo debes pasar defaultValue
:
// ✅ Bien: text area no controlado con un valor inicial
<textarea defaultValue={algo} />
Si quieres controlar este text area con una variable de estado, especifica un manejador onChange
:
// ✅ Bien: text area controlado con onChange
<textarea value={algo} onChange={e => asignaAlgo(e.target.value)} />
Si el valor es de sólo lectura intencionalmente, agrega la prop readOnly
para evitar el error:
// ✅ Bien: text area controlado de solo lectura sin onChange
<textarea value={algo} readOnly={true} />
El caret de mi text area salta al inicio con cada pulsación de tecla
Si controlas un text area, debes actualizar su variable de estado al valor del text area del DOM durante onChange
.
No puedes actualizarlo a algo más que no sea e.target.value
:
function handleChange(e) {
// 🔴 Error: actualizar un input a algo que no sea e.target.value
asignaPrimerNombre(e.target.value.toUpperCase());
}
Tampoco puedes actualizarlo de manera asíncrona:
function handleChange(e) {
// 🔴 Error: actualizar un input de manera asíncrona
setTimeout(() => {
asignaPrimerNombre(e.target.value);
}, 100);
}
Para arreglar tu código, actualízalo de manera síncrona a e.target.value
:
function handleChange(e) {
// ✅ Actualizar un input controlado a e.target.value de manera síncrona
asignaPrimerNombre(e.target.value);
}
Si esto no arregla el problema, es posible que el text area esté siendo removido y agregado nuevamente al DOM con cada pulsación de tecla. Esto puede suceder si estás reiniciando el estado accidentalmente en cada re-renderización. Por ejemplo, esto puede suceder si el text area o uno de sus padres siempre recibe un atributo key
diferente, o si anidas definiciones de componentes (lo cual no está permitido en React y causa que el componente de “adentro” sea re-montado en cada renderización).
Estoy obteniendo un error: “A component is changing an uncontrolled input to be controlled”
Si proporcionas un value
al componente, este valor debe mantenerse como string durante todo su tiempo de vida.
No puedes pasar value={undefined}
primero y después pasar value="un string"
porque React no sabrá si quieres que el componente sea controlado o no controlado. Un componente controlado siempre debe recibir un value
string, no null
o undefined
.
Si tu value
viene de una API o una variable de estado, esta podría ser inicializada como null
o undefined
. En ese caso, asígnala a un string vacío (''
) inicialmente, o pasa value={someValue ?? ''}
para asegurar que value
es un string.