Un formulario de registro puede sentirse lento aunque la red responda rápido. Basta con que el mensaje de validación aparezca debajo del campo y empuje todo el contenido para que el botón cambie de posición justo cuando el usuario intenta pulsarlo. Ese pequeño salto afecta la confianza y complica la navegación con teclado.
Al trabajar con formularios en React, me resulta útil tratar la validación como un problema de diseño de estados, no solo como una expresión regular. Un usuario puede ver el campo vacío, un aviso local, una comprobación en progreso, un error del servidor o una confirmación. Si cada estado tiene una geometría previsible, la interfaz se siente más estable y el rendimiento percibido mejora.
El problema: validar cambia el tamaño de la interfaz
El caso típico es un div que solo se renderiza cuando el email es inválido:
{error && <p className="error">Escribe un email válido.</p>}
El código es correcto, pero el párrafo no ocupa espacio antes de que exista el error. Cuando aparece, mueve los controles siguientes. El usuario entiende que algo pasó, pero tambien puede perder el foco visual o hacer clic en otro elemento.
La solución no es ocultar el mensaje. Los errores deben ser visibles, estar asociados al campo y explicar cómo continuar. El objetivo es reservar una zona estable para ese mensaje y cambiar su contenido sin cambiar innecesariamente la composición.
Reserva espacio para cada estado
Una opción sencilla es dar una altura mínima al contenedor del mensaje. El valor exacto depende de la tipografía y del diseño, pero debe cubrir una o dos líneas en móvil:
.fieldMessage {
min-height: 1.5rem;
margin-top: 0.35rem;
color: #b42318;
font-size: 0.875rem;
line-height: 1.5;
}
.fieldMessage:empty {
visibility: hidden;
}
visibility: hidden conserva el espacio sin presentar texto a la vista. Para un estado vacío es una elección más segura que display: none cuando la estabilidad visual importa. Si el mensaje puede ocupar más de una línea, usa una altura mínima generosa y prueba la versión con zoom del navegador.
También conviene reservar espacio para un indicador de estado. Un formulario que cambia directamente de “comprobar” a “email no disponible” puede parpadear. Una zona con texto corto y estable resulta mas facil de leer que un spinner sin explicación.
React y CSS para mensajes previsibles
El componente puede mantener un estado explícito y una relación clara entre el label, el input y el mensaje:
type EmailState = "idle" | "checking" | "valid" | "invalid";
function EmailField({ state, message }: {
state: EmailState;
message: string;
}) {
const hasError = state === "invalid";
return (
<div className="field">
<label htmlFor="email">Email</label>
<input
id="email"
name="email"
type="email"
aria-invalid={hasError}
aria-describedby="email-message"
/>
<p id="email-message" className="fieldMessage" aria-live="polite">
{message}
</p>
</div>
);
}
El mensaje debe cambiar cuando cambia el estado, no como efecto secundario de un render inesperado. aria-live="polite" permite anunciar el resultado sin interrumpir cada pulsación. Para errores críticos puede ser necesario otro nivel de urgencia, pero no conviene convertir cada validación local en una alarma.
En validaciones asíncronas, cancela o ignora respuestas antiguas. Una respuesta lenta para ana@ejemplo.com no debe reemplazar el resultado más nuevo de ana@ejemplo.org. Este detalle evita mensajes contradictorios y reduce el trabajo visual que el usuario tiene que interpretar. Un registro de eventos pequeño también ayuda: aquí sirven logs útiles para una cola de email para separar una respuesta tardía de un error real.
Accesibilidad sin perder rendimiento
La estabilidad de layout y la accesibilidad se refuerzan. Un mensaje que aparece lejos del campo es dificil de relacionar; un mensaje que mueve el botón puede causar activaciones accidentales. Mantén el texto cerca del control, pero evita que el contenido cambiante fuerce toda la página a recolocarse.
Hay cuatro comprobaciones rápidas:
- Navega el formulario solo con teclado y confirma que el foco no salta.
- Comprueba que
aria-describedbyapunta a un nodo que siempre existe. - Prueba mensajes largos con aumento de texto y una pantalla estrecha.
- Respeta
prefers-reduced-motionsi usas transiciones en el mensaje.
En un formulario que acepta una dirección de prueba o un generador de correo falso, la interfaz debe seguir explicando el estado sin asumir que el usuario ve el color. El color ayuda, pero el texto, el icono con nombre accesible y aria-invalid llevan la información principal. Para revisar patrones de foco y avisos, consulta estos warnings de React sin robar el foco.
Si necesitas probar una confirmación de entrega, un correo temporal puede separar el escenario de pruebas de una bandeja personal. El test debe verificar también el estado de la UI: mensaje visible, foco conservado y botón habilitado o deshabilitado según la regla. No basta con comprobar que llegó un email.
Q&A: dudas habituales
¿Debo validar mientras el usuario escribe?
No siempre. La validación local de formato puede ocurrir después de que el campo pierda el foco o cuando hay una pausa breve. Validar en cada tecla suele producir demasiado ruido. La disponibilidad o confirmación remota debería tener una acción explícita y un estado de carga entendible.
¿Una altura fija siempre evita los saltos?
No. El texto puede envolver en pantallas pequeñas, cambiar con la localización o crecer por preferencias de accesibilidad. Usa min-height, prueba varios anchos y permite que el contenedor crezca cuando haga falta. Es mejor un movimiento ocasional y comprensible que texto cortado.
¿Qué hago con un dato de prueba como temp mailid?
Trátalo como un caso negativo de datos, no como una dirección válida ni como un enlace. El estado del formulario debe explicar el formato esperado sin exponer detalles internos del test.
Checklist final
- El mensaje de validación tiene una región reservada.
- El campo conserva foco y usa
aria-invalidcuando corresponde. -
aria-describedbyapunta a un elemento estable. - Los estados local, remoto y de error tienen textos distintos.
- Las respuestas asíncronas antiguas no pisan el resultado actual.
- El diseño funciona con zoom, móvil y mensajes de dos líneas.
- Las pruebas revisan la interfaz además del correo recibido.
Una validación bien diseñada no solo rechaza entradas incorrectas. Hace visible qué está pasando, mantiene el formulario tranquilo y deja que React, CSS y las ayudas de accesibilidad trabajen en la misma dirección.
Top comments (0)