acerca de HTML

Referencia de etiquetas

Etiqueta textarea en HTML: texto multilínea y límites

La etiqueta <textarea> en HTML crea un campo para introducir y editar texto de varias líneas. Úsala para un mensaje de contacto, una reseña o una descripción que pueda necesitar párrafos. A diferencia de <input type="text">, permite insertar saltos de línea con Enter; aumentar la altura de un <input> con CSS no le da esa capacidad.

<label for="mensaje">Mensaje</label>
<textarea id="mensaje" name="mensaje" rows="4" maxlength="500"></textarea>

Verás un campo vacío, etiquetado «Mensaje», con espacio inicial para cuatro líneas y un límite de 500 unidades de texto. Prueba el fragmento dentro del <body> de un documento HTML con codificación UTF-8: pulsa la etiqueta, escribe y usa Enter. No necesita JavaScript. El campo aislado no envía nada; name="mensaje" identifica su dato cuando se asocia a un formulario.

Sintaxis, contenido y texto inicial

Escribe apertura y cierre: <textarea>texto inicial</textarea>. Ninguna etiqueta puede omitirse y <textarea /> no cierra el elemento en HTML. Se permite donde se admite contenido de frase, por ejemplo dentro de un formulario o un párrafo. Su contenido es texto, según el modelo de contenido de WHATWG.

¿Cómo pongo texto inicial? Escríbelo entre las etiquetas:

<label for="consulta">Consulta</label>
<textarea id="consulta" name="consulta" rows="3">Quisiera reservar una visita.
¿Qué horarios tienen?</textarea>

El campo empieza con esas dos líneas, editables. La indentación también cuenta como texto: evita añadir espacios para alinear su contenido con el resto del código. El analizador HTML elimina un salto de línea inmediatamente después de la apertura; otros saltos y espacios se conservan. La sintaxis HTML del estándar describe esta excepción.

Para mostrar literalmente <strong> o &, escribe &lt;strong&gt; o &amp;. El contenido no se convierte en negrita ni ejecuta etiquetas. Escapar < también evita que una cadena como </textarea> cierre el campo antes de tiempo.

Valor inicial, value y restablecimiento

¿Por qué no funciona value como atributo? <textarea value="Hola"></textarea> es un uso incorrecto: el elemento define su valor inicial mediante el contenido textual, y en ese ejemplo sigue vacío. placeholder="Hola" tampoco establece un valor; solo muestra una sugerencia cuando el campo está vacío.

JavaScript utiliza propiedades del elemento. Añade este script después del campo consulta:

<script>
const campo = document.getElementById("consulta");
console.log(campo.value);         // Texto actual, incluidas las ediciones.
console.log(campo.defaultValue);  // Texto inicial entre las etiquetas.
campo.value = "Otra consulta";    // Cambia el texto actual.
</script>

Ejecuta este fragmento después de crear el campo consulta. .value lee o cambia el valor actual; .defaultValue refleja el contenido textual que sirve de valor predeterminado. Asignar .value no cambia ese valor predeterminado. Si quieres cambiarlo también, modifica .defaultValue.

Dentro de un formulario, un botón type="reset" o formulario.reset() devuelve el campo al valor predeterminado, no necesariamente a una cadena vacía. Si lo dejaste vacío en el HTML, se vaciará; si escribiste una consulta inicial, la recuperará.

Atributos, longitud y ajuste de líneas

Estos atributos propios de controles de formulario cumplen funciones distintas:

  • name: nombre del dato, como name="mensaje". Sin él, el texto no se incluye en los datos del formulario; id no lo sustituye.
  • rows y cols: líneas visibles y anchura orientativa en caracteres. Admiten enteros positivos; los valores predeterminados son 2 y 20. No limitan cuántas líneas puedes escribir ni fijan un tamaño CSS inmutable.
  • maxlength y minlength: límites máximo y mínimo, enteros no negativos. El mínimo no obliga a rellenar un campo opcional; añade required para exigir contenido. Si usas ambos, el mínimo no puede superar el máximo.
  • required: impide validar un valor vacío. No significa que el mensaje tenga contenido útil: unos espacios pueden cumplir el requisito.
  • placeholder: pista breve; no reemplaza la etiqueta, la ayuda ni el texto inicial.
  • readonly: permite enfocar, seleccionar y copiar, pero impide editar. Su valor puede incluirse en el formulario; el control queda fuera de la validación de restricciones.
  • disabled: deshabilita la interacción, normalmente lo excluye del recorrido con Tab y excluye su dato del envío. Consulta las referencias de solo lectura y deshabilitación.
  • wrap: soft, predeterminado, ajusta la presentación sin añadir saltos automáticos al dato; conserva los escritos con Enter. hard añade saltos al dato recogido para el envío según la anchura; acompáñalo de cols. No limita la longitud total del mensaje.
  • autocomplete: sugiere el autocompletado con on, off o tokens adecuados al dato. Sin él, hereda el estado del formulario; el navegador decide cómo aplicar la sugerencia. Consulta los valores de autocompletado.
  • form: asocia el campo al <form> cuyo id indica, aunque esté fuera: form="contacto". Sin él, se asocia al formulario antecesor, si existe; también puede existir sin formulario.

required, readonly y disabled son booleanos: su presencia los activa. disabled="false" sigue deshabilitando; retira el atributo para habilitar.

Los límites maxlength y minlength miden unidades UTF-16, igual que .value.length: ciertos emojis ocupan dos unidades y un símbolo visible puede combinar varias. Los saltos en .value se normalizan a \n y cuentan una unidad. No prometas «500 símbolos visibles». El navegador normalmente evita superar el máximo al escribir, pero asignar texto por JavaScript no lo recorta automáticamente; la validación de longitud depende de ediciones del usuario. Un servidor real debe comprobar sus propios límites.

id, class y lang son atributos globales; aria-describedby asocia ayuda accesible. width, height y resize son propiedades CSS; .value y .defaultValue son propiedades DOM. Cambiar la apariencia conserva la función multilínea.

Ejemplo práctico: contacto con contador y errores

Guarda este documento completo como contacto.html en UTF-8 y ábrelo en el navegador. Incluye su CSS y JavaScript; no necesita archivos adicionales ni servidor. La demostración no envía mensajes ni guarda datos. El botón de comprobación empieza deshabilitado y solo se habilita al ejecutar el script. Sin JavaScript permanecen la etiqueta, la ayuda, el campo editable y el restablecimiento.

<!doctype html>
<html lang="es">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Consulta al taller</title>
    <style>
      body { font: 1rem/1.5 system-ui; margin: 1rem; }
      #contacto { max-width: 36rem; }
      #contacto label { display: block; font-weight: bold; }
      #contacto textarea {
        box-sizing: border-box;
        width: 100%;
        min-height: 8rem;
        font: inherit;
        resize: vertical;
      }
      #contacto :focus-visible { outline: 3px solid #174ea6; outline-offset: 3px; }
      #contacto-error { color: #9b1c1c; }
    </style>
  </head>
  <body>
    <h1>Consulta al taller</h1>
    <p>Prueba local: no se enviará ningún mensaje.</p>
    <form id="contacto">
      <label for="contacto-mensaje">Mensaje (obligatorio)</label>
      <p id="contacto-ayuda">Escribe entre 20 y 500 unidades de texto.
        Puedes usar varias líneas; algunos emojis cuentan como dos unidades.</p>
      <textarea id="contacto-mensaje" name="mensaje" rows="5" cols="40"
                minlength="20" maxlength="500" required wrap="soft"
                aria-describedby="contacto-ayuda contacto-error"></textarea>
      <p id="contacto-contador" hidden>Longitud actual: <span>0</span> de 500.</p>
      <p id="contacto-error" hidden></p>
      <button id="contacto-comprobar" type="button" disabled>Comprobar mensaje</button>
      <button type="reset">Restablecer</button>
      <p id="contacto-estado" role="status"></p>
    </form>
    <noscript><p>El contador y la comprobación local necesitan JavaScript.
      Puedes escribir y restablecer el texto; no se envía nada.</p></noscript>
    <script>
      const formulario = document.getElementById("contacto");
      const mensaje = document.getElementById("contacto-mensaje");
      const contador = document.getElementById("contacto-contador");
      const error = document.getElementById("contacto-error");
      const estado = document.getElementById("contacto-estado");
      const comprobar = document.getElementById("contacto-comprobar");

      function actualizarContador() {
        contador.querySelector("span").textContent = mensaje.value.length;
      }

      function limpiarAvisos() {
        error.hidden = true;
        error.textContent = "";
        mensaje.removeAttribute("aria-invalid");
        estado.textContent = "";
      }

      formulario.addEventListener("submit", (evento) => evento.preventDefault());
      mensaje.addEventListener("input", () => {
        actualizarContador();
        limpiarAvisos();
      });
      comprobar.addEventListener("click", () => {
        limpiarAvisos();
        if (!mensaje.checkValidity()) {
          error.textContent = mensaje.validity.valueMissing
            ? "Error: escribe un mensaje."
            : "Error: el mensaje debe tener entre 20 y 500 unidades de texto.";
          error.hidden = false;
          mensaje.setAttribute("aria-invalid", "true");
          mensaje.focus();
          return;
        }
        estado.textContent = "Mensaje válido para esta prueba. No se envió nada.";
      });
      formulario.addEventListener("reset", () => {
        limpiarAvisos();
        // El evento ocurre antes de restaurar el valor del campo.
        setTimeout(actualizarContador, 0);
      });

      actualizarContador();
      contador.hidden = false;
      comprobar.disabled = false;
    </script>
  </body>
</html>

Prueba estos pasos:

  1. Con Tab llega al campo, escribe Necesito una revisión. y pulsa Enter para añadir otra línea. Verás el contador actualizarse y podrás ampliar el campo verticalmente con su tirador, si el navegador lo ofrece.
  2. Llega a «Comprobar mensaje» con Tab y actívalo con Enter o Espacio. Con ese texto verás la confirmación local. Enter dentro del campo escribe un salto; no comprueba ni envía el mensaje.
  3. Vacía el campo o escribe Hola y comprueba otra vez. Verás un error textual, asociado al campo mediante aria-describedby, y el foco volverá al campo marcado con aria-invalid. Al editar se limpia el aviso anterior.
  4. Pulsa «Restablecer»: recuperarás el valor inicial vacío y el contador volverá a cero. Añadir texto entre las etiquetas cambia también lo que recupera este botón.
  5. Deshabilita JavaScript y recarga. Podrás escribir, leer la ayuda y restablecer; el contador estará oculto y la comprobación deshabilitada.

El contador es una ayuda visual opcional: no se anuncia como región viva en cada pulsación. La confirmación usa role="status"; los errores se comunican con texto y asociación, además del color. El CSS permite ampliar la altura; evita resize: none cuando el lector pueda necesitar más espacio.

Errores frecuentes y elección de etiquetas

Si no aparece el texto inicial, comprueba primero que esté entre apertura y cierre, que no uses un atributo value y que ningún script sobrescriba .value. Si falta el dato al recoger el formulario, revisa name, disabled y la asociación form. Si el campo tiene espacios al cargar, revisa su indentación.

Retirar <textarea> dejando su contenido convierte el mensaje en texto de la página: deja de ser editable y no aporta un dato al formulario. Sustituirlo por <input type="text"> crea un control de una sola línea; sustituirlo por un <div> no crea un control de formulario nativo.

  • Usa <input> para una línea o un tipo específico, como correo o fecha.
  • Usa <label> para nombrar el campo de forma visible y asociada; el placeholder desaparece al escribir.
  • Usa <form> para reunir controles y configurar un envío real con un destino que procese los datos.
  • Usa <output> para un resultado calculado, como un total; no permite editar un mensaje. Su semántica de resultado puede anunciar actualizaciones, por lo que este contador utiliza un <span> sencillo.

Compatibilidad y fuentes

<textarea> está disponible en los navegadores actuales. La referencia y compatibilidad de MDN distingue el elemento y sus atributos. La apariencia, el tirador de redimensionado y el autocompletado pueden variar entre navegador y dispositivo; no dependas de un aspecto idéntico. Los ejemplos usan el control nativo, límites habituales y propiedades DOM establecidas, sin una función experimental.

Consulta el HTML Living Standard para <textarea> para la definición normativa y wrap, y las referencias enlazadas en cada sección para valores, validación y restablecimiento. Fuentes revisadas el 4 de octubre de 2026.