<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="postContent" />
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 controlador 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
: Puede ser'on'
u'off'
. Especifica el comportamiento de autocompletar.autoFocus
: Un booleano. Si estrue
, React enfocará el elemento en el montaje.children
:<textarea>
no acepta hijos. Para establecer el valor inicial, utilizadefaultValue
.cols
: Un número. Especifica el ancho por defecto en anchos promedio de caracteres. 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 más 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 controladora deevento
. 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 controladora deevento
. 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 controladora deevento
. 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 controladora deevento
. 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
: Puede ser'hard'
,'soft'
, u'off'
. Especifica cómo debe envolverse el texto al enviar un formulario.
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 controlador 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 NewPost() { return ( <label> Escribe tu mensaje: <textarea name="postContent" 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 haga 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>
, asócialos 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 Form() { const postTextAreaId = useId(); return ( <> <label htmlFor={postTextAreaId}> Escribe tu mensaje: </label> <textarea id={postTextAreaId} name="postContent" 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 EditPost() { return ( <label> Edita tu mensaje: <textarea name="postContent" defaultValue="¡Yo realmente disfruté del ciclismo 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 controlador de evento <form onSubmit>
. Por defecto, el navegador enviará 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 EditPost() { 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 mensaje: <input name="postTitle" defaultValue="Ciclismo" /> </label> <label> Edita tu mensaje: <textarea name="postContent" defaultValue="¡Yo realmente disfruté del ciclismo ayer!" rows={4} cols={40} /> </label> <hr /> <button type="reset">Reiniciar edición</button> <button type="submit">Guardar mensaje</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 NewPost() {
const [postContent, setPostContent] = useState(''); // Declara una variable de estado...
// ...
return (
<textarea
value={postContent} // ...fuerza al valor del input a que coincida con la variable de estado...
onChange={e => setPostContent(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 MarkdownEditor() { const [postContent, setPostContent] = useState('¡_Hola,_ **Marcado**!'); return ( <> <label> Ingrese algún marcado: <textarea value={postContent} onChange={e => setPostContent(e.target.value)} /> </label> <hr /> <MarkdownPreview markdown={postContent} /> </> ); }
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 controlador onChange
<textarea value={something} />
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
.value
a un campo de formulario sin un controlador onChange
. Esto renderiza un campo de solo lectura. Si el campo debe ser mutable usa defaultValue
. En caso contrario, establece onChange
o 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={something} />
Si quieres controlar este text area con una variable de estado, especifica un controlador onChange
:
// ✅ Bien: text area controlado con onChange
<textarea value={something} onChange={e => setSomething(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={something} 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
setFirstName(e.target.value.toUpperCase());
}
Tampoco puedes actualizarlo de manera asíncrona:
function handleChange(e) {
// 🔴 Error: actualizar un input de manera asíncrona
setTimeout(() => {
setFirstName(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
setFirstName(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.