Crea un contador de caracteres para textarea con JavaScript. Actualiza al escribir o pegar y distingue el límite nativo del recuento de símbolos.
Un contador que sigue los cambios reales
Un contador de caracteres JavaScript ayuda a redactar un mensaje con un límite conocido. Escucha input para cubrir escritura, pegado y otras modificaciones de entrada. Keyup no representa todos esos cambios y puede dejar un número desactualizado. El ejemplo también calcula el estado inicial, porque el campo podría llegar con contenido precargado.
Límite y recuento deben significar lo mismo
La longitud de una cadena en JavaScript utiliza unidades UTF-16. Algunos símbolos visibles ocupan más de una unidad. El límite nativo de este control sigue una medida relacionada, por lo que el indicador debe explicarse según esa regla. No prometas que cada emoji equivale siempre a un carácter contado. Si el producto necesita contar grafemas, utiliza una estrategia específica y revisa también cómo validará el servidor.
Código completo para probar en tu navegador
Copia este documento en un archivo index.html, guarda los cambios y ábrelo en el navegador. El ejemplo no requiere bibliotecas.
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contador de caracteres para textarea con JavaScript</title>
<style>
*{box-sizing:border-box}body{font:16px/1.6 system-ui,sans-serif;max-width:900px;margin:2rem auto;padding:1rem;color:#17233b}label{display:block;font-weight:700;margin-top:1rem}input,textarea,select,button{font:inherit;padding:.65rem;max-width:100%}textarea{width:100%}button{cursor:pointer}button:focus-visible,a:focus-visible{outline:3px solid #173b94;outline-offset:3px}[hidden]{display:none!important}[role=tab][aria-selected=true]{background:#173b94;color:white}[role=tab]{border:1px solid #bdcbe2;border-radius:.5rem}[role=tabpanel]{padding:1rem;border:1px solid #bdcbe2}
</style>
</head>
<body>
<label for="mensaje">Mensaje (máximo 280)</label>
<textarea id="mensaje" maxlength="280" aria-describedby="cantidad"></textarea>
<p id="cantidad"></p>
<script>
const mensaje = document.querySelector('#mensaje');
const cantidad = document.querySelector('#cantidad');
function contar() {
cantidad.textContent = mensaje.value.length + ' de ' + mensaje.maxLength;
}
mensaje.addEventListener('input', contar);
contar();
</script>
</body>
</html>Una etiqueta que permanece visible
La ayuda se relaciona con el textarea y permanece junto a él. No necesitas anunciar cada pulsación mediante una región viva: una sucesión constante de números puede resultar molesta con lectura asistida. Si deseas avisar cuando se aproxima el límite, anuncia únicamente cambios relevantes. Mantén visible el máximo antes de que la persona escriba para que pueda planificar el mensaje.
Evitar truncados inesperados
No recortes silenciosamente un texto ya redactado al enviar si puedes explicar la condición antes. Maxlength ayuda durante la entrada, pero la validación final debe existir en el servidor. Una petición construida fuera de la interfaz puede enviar otros datos. Decide además si el producto admite guardar un borrador largo o si el límite impide continuar. El contador informa; no sustituye el diseño del flujo.
Texto precargado y cambios programáticos
Modificar value desde otro script no garantiza que se dispare input. Después de cargar una plantilla o limpiar el formulario, llama a contar explícitamente. Esa actualización debe formar parte de la misma acción que cambia el dato. Si utilizas varios campos, mantén una relación por contenedor y evita que todos escriban sobre el mismo mensaje de ayuda.
Casos para comprobarlo
Prueba vacío, una palabra, varias líneas y un pegado cercano al máximo. Incluye tildes y emoji para observar la diferencia entre símbolos y unidades. Después cambia el contenido mediante otro botón y comprueba si actualizaste el indicador. Vuelve a abrir el formulario cuando exista un borrador y confirma que el número inicial corresponde al valor recuperado.
Adaptación de la presentación
Coloca el indicador en una zona que no tape el texto ni quede fuera al ampliar la tipografía. Un cambio de color puede reforzar cercanía al máximo, pero debe acompañarse de cifras comprensibles. No disminuyas el contraste del contador hasta convertirlo en decoración ilegible. La persona lo necesita precisamente cuando debe tomar una decisión sobre cuánto puede escribir.
Integración con el envío
Mantén el atributo name cuando el campo pertenezca a un formulario real. Id relaciona etiquetas y selectores, mientras name identifica el dato que se envía. Tras un error, conserva lo escrito y recalcula el indicador. Mostrar un cero mientras el texto sigue en pantalla crea una contradicción. Revisa este recorrido junto al proceso de validación, no únicamente con un textarea aislado.
Emojis y unidades de longitud
El contador del ejemplo utiliza la misma unidad práctica que la restricción nativa del campo: unidades de código UTF-16. Eso significa que un símbolo visible puede ocupar más de una unidad. Un emoji compuesto, una bandera o una letra con marcas combinadas pueden consumir un número que no coincide con la cantidad de dibujos que ves. No lo presentes como un recuento universal de letras. Si tu producto necesita contar caracteres percibidos, puedes estudiar Intl.Segmenter con granularidad de grafema y definir una política distinta de límite. En ese caso también deberás revisar la validación del servidor y la forma de impedir excesos; cambiar solamente el contador produciría mensajes contradictorios.
Pegar, dictar y usar composición de texto
input responde a cambios del valor realizados por varias formas de entrada, no solamente a una tecla. Por eso resulta más adecuado que keyup para pegar texto, dictar o utilizar herramientas del dispositivo. Aun así, prueba los métodos de entrada que usa tu público, especialmente los que componen caracteres en varias etapas. No cortes el valor en cada pulsación con un substring sin considerar ese proceso. El límite nativo ofrece una base sencilla. Si añades validación personalizada, evita interrumpir una composición o mover el cursor al final después de cada actualización, porque eso hace muy difícil corregir una frase en medio del mensaje.
Mensajes de ayuda cerca del límite
Puedes cambiar el texto cuando queden pocas unidades disponibles, por ejemplo Quedan 20 de 280. Mantén la relación con aria-describedby y utiliza palabras además del color. Una cifra roja sin explicación no indica si el formulario está bloqueado o simplemente próximo al máximo. Evita un anuncio automático por cada carácter: escuchar una cuenta continua dificulta redactar. Si necesitas comunicar un umbral, hazlo solamente cuando se cruce y comprueba que no se repita con cada corrección. El contador principal puede seguir visible y consultable sin convertirse en una región que interrumpe constantemente.
Una prueba de precarga y restauración
Escribe un mensaje, actualiza la página y comprueba qué restaura el navegador. Después introduce un valor inicial desde tu aplicación y llama a contar tras asignarlo. Cambiar value desde JavaScript no dispara automáticamente el evento input como una escritura normal. También debes decidir qué hacer si un dato antiguo supera el límite actual: mostrar una explicación suele ser mejor que borrarlo silenciosamente. Para formularios con borrador, conserva el texto original hasta que la persona pueda revisarlo. Un contador útil acompaña la edición y señala reglas; no modifica contenido importante sin una decisión explícita.
Separar el límite del aviso de envío
El contador informa mientras se redacta, pero el envío todavía necesita una comprobación coherente. Si el servidor admite una longitud distinta, explica la regla real y ajusta el campo para evitar sorpresas. Prueba también mensajes con saltos de línea y texto copiado desde un procesador de documentos. No sustituyas silenciosamente caracteres para hacerlos caber. Si un mensaje supera una regla de negocio, conserva su contenido y muestra qué debe corregirse. La persona debería poder editarlo sin empezar de nuevo ni perder una idea que todavía no había guardado.
Guías relacionadas para seguir practicando
Puedes ampliar esta práctica con Estructurar un formulario y Gestionar eventos de entrada.




