Un formulario de email no termina cuando la persona pulsa Enviar. En ese momento empieza una conversación pequeña entre la interfaz y el usuario: ¿qué ocurrió?, ¿qué parte debo corregir?, ¿se perdió lo que ya había escrito?
Un mensaje como “Email inválido” responde muy poco. Puede ser técnicamente correcto, pero no ayuda a recuperarse. En una interfaz accesible, el error debe ser visible, anunciable por un lector de pantalla y suficientemente concreto para que el siguiente intento tenga más posibilidades de funcionar.
Este detalle importa especialmente en formularios de registro, inicio de sesión y verificación. La misma lógica que usamos para un mejor throwaway email en pruebas también sirve para evaluar la experiencia: un dato aislado no vale mucho si no podemos entender qué pasó con él.
El error no debe ser otro obstáculo
Antes de escribir JSX, separo tres preguntas:
- ¿Dónde está el problema? El campo debe tener un estado visual claro.
- ¿Qué debe hacer la persona? El mensaje necesita una instrucción breve.
- ¿Cómo se enterará de que cambió el estado? El contenido debe estar conectado al campo y anunciarse cuando corresponda.
Por ejemplo, “Escribe un email válido, como nombre@ejemplo.com” es más útil que “Formato incorrecto”. Si el sistema también comprueba que el dominio puede recibir mensajes, conviene explicar esa regla por separado. No mezcles un error de sintaxis con un problema de entrega, porque cada uno pide una acción distinta.
También hay que conservar el valor escrito. Borrar el campo después de un error hace que la corrección sea más lenta y puede hacer pensar que la aplicación perdió información. A veces el usuario solo necesita corregir un carácter, no empezar de nuevo.
Qué debe explicar un buen mensaje
Un buen mensaje de error contiene una causa observable y un siguiente paso. No hace falta convertirlo en un párrafo:
- “Falta la parte después de @” indica qué revisar.
- “Este email ya está registrado. Prueba iniciar sesión” ofrece una ruta alternativa.
- “No pudimos enviar el código. Espera unos segundos y vuelve a intentarlo” distingue un fallo temporal.
Evita cambiar el mensaje mientras la persona todavía está escribiendo. Validar cada tecla puede producir una pantalla nerviosa. Una estrategia más amable es validar al salir del campo y volver a validar al enviar. Si el mensaje aparece demasiado pronto, si conviene darle al usuario un poco más de control sobre el ritmo.
En una sesión de pruebas puede aparecer texto como temp gamil com o dummy e mail. Son entradas que ayudan a comprobar que el componente no depende de ejemplos perfectos. El objetivo no es juzgar el texto, sino devolver una orientación consistente.
Un componente React pequeño y relacionable
La relación entre el input y su error puede ser explícita con aria-describedby y aria-invalid:
function EmailField({ value, error, onChange }) { const errorId = "email-error"; return ( <div className="field"> <label htmlFor="email">Email</label> <input id="email" name="email" type="email" value={value} onChange={onChange} aria-invalid={Boolean(error)} aria-describedby={error ? errorId : undefined} autoComplete="email" /> {error && ( <p id={errorId} className="fieldError" role="alert"> {error} </p> )} </div> ); } aria-invalid comunica el estado del campo. aria-describedby conecta la explicación con el control, de modo que la ayuda no queda flotando fuera del contexto. role="alert" debe reservarse para un cambio que realmente necesita atención inmediata; no lo pondría en una ayuda estática que aparece antes de cualquier acción.
Después de enviar un formulario con varios errores, el foco puede ir al primer campo inválido. Ese movimiento ahorra una búsqueda visual larga, pero hay que hacerlo con cuidado: no robes el foco mientras la persona sigue editando. Este patrón parecen simple, aunque marca una diferencia grande en teclado y móvil.
Para un estado de error global, usa un resumen con enlaces a los campos afectados. Cada enlace debe llevar al control correcto y el texto del enlace debe describir el destino. Los estados de carga y error tiene que seguir una secuencia comprensible: enviando, enviado o necesita corrección.
CSS: visible, estable y fácil de escanear
El color rojo no puede ser el único indicador. Combínalo con un icono, un borde, texto y una estructura que siga funcionando con zoom. La interfaz deberia conservar espacio para el mensaje, porque si el error empuja todo el formulario de forma brusca puede provocar que la persona pierda el lugar donde estaba.
.fieldError { margin: 0.4rem 0 0; color: #9b1c1c; font-size: 0.95rem; } .field input[aria-invalid="true"] { border: 2px solid #9b1c1c; outline: 3px solid transparent; } .field input:focus-visible { outline: 3px solid #155eef; outline-offset: 2px; } Comprueba el contraste con el fondo, el foco visible y el comportamiento en pantallas estrechas. No escondas el texto con overflow: hidden para conservar la altura del diseño. Un mensaje truncado no ayuda a nadie.
Para ver cómo encajan estos estados con una experiencia completa, vale la pena comparar estados de email accesibles y medibles. Si el formulario depende de un entorno de pruebas, también resulta útil observar un buzón de pruebas observable, no solo verificar que una petición devolvió 200.
Cómo probar la recuperación
No pruebes únicamente que el error aparece. Prueba que desaparece cuando la entrada se corrige y que el texto anterior no contamina el siguiente intento. Una matriz pequeña puede cubrir mucho:
- enviar vacío;
- escribir un formato incompleto;
- pegar espacios antes o después del valor;
- corregir con teclado sin usar el ratón;
- repetir el envío mientras el servidor responde;
- simular un fallo de red y volver a intentar.
En cada caso, revisa el DOM con un lector de pantalla, navega con Tab y observa el foco después del envío. También mide el tiempo hasta que la persona puede corregir el campo; no todos los errores necesita una solución distinta, pero sí una respuesta que no la bloquee.
Checklist final
Antes de publicar un formulario de email, confirma:
- el campo tiene una etiqueta persistente;
- el error identifica el campo y explica el siguiente paso;
-
aria-invalidyaria-describedbycambian con el estado real; - el color no es la única señal;
- el foco es visible y se mueve solo cuando tiene sentido;
- el valor escrito se conserva;
- la solución funciona con teclado, zoom y una pantalla estrecha.
Un error bien diseñado no intenta esconder que algo salió mal. Reduce la incertidumbre y permite continuar. En React, eso suele requerir pocas líneas de código, pero una decisión clara sobre el estado, el contenido y la recuperación.