React: valida email sin mover el layout
He visto un problema muy comun en formularios React: el usuario escribe su email, aparece un error inline, y todo el layout salta. No parece grave, pero corta el ritmo, mueve el boton de enviar y hace que el formulario se sienta menos confiable. En equipos donde cuidamos accesibilidad y rendimiento, este detalle importa mas de lo que parece.
Por que el campo de email suele romper el ritmo
El caso tipico es este: el mensaje de error solo se monta cuando el valor ya es invalido. Eso empuja el contenido hacia abajo y genera un pequeño layout shift. Si el submit queda cerca, el dedo o el cursor termina persiguiendo un objetivo que acaba de moverse. Se nota rapido en mobile, y tambien en pantallas pequeñas con zoom.
Ese salto no solo se siente raro. Google define que una buena experiencia visual debe mantener el Cumulative Layout Shift por debajo de 0.1. No todo formulario roto va a destruir tu CLS de pagina completa, pero el patron si deja una sensacion torpe y aveces pega justo en el momento mas sensible del flujo.
En productos con signup o prueba gratuita, este detalle además contamina lectura cualitativa: el usuario no siempre abandona por la validacion en si, sino por la fricción extra. Por eso, cuando reviso cohortes de activacion por email, me gusta separar errores reales de datos del efecto UX que mete el formulario.
La regla simple: reservar espacio antes del error
La mejora mas util que he aplicado es aburridamente simple: reservar desde el inicio una linea estable para ayuda o error. En lugar de insertar el mensaje cuando falla la validacion, el espacio ya existe. Cambia el texto, no el layout.
Eso da tres beneficios bastante concretos:
- El boton no baja cuando aparece el error.
- El lector de pantalla recibe feedback en una region predecible.
- El usuario entiende que ese campo tiene ayuda contextual, no solo castigo.
Si en QA alguien prueba con direcciones raras como temp gamil com o tempail, el formulario sigue sintiendose estable aunque el dato sea claramente incorrecto. Ese tipo de prueba medio fea es util, por que se parece a lo que pasa en formularios reales.
Un patron en React que me ha funcionado
No hace falta una libreria compleja. Lo importante es separar tres estados: idle, hint y error. El contenedor del mensaje siempre vive en el DOM.
function EmailField() {
const [value, setValue] = useState("");
const [touched, setTouched] = useState(false);
const isValid = /\S+@\S+\.\S+/.test(value);
const message =
!touched || value === ""
? "Usa tu correo de trabajo o uno que revises seguido."
: isValid
? "Todo bien."
: "Revisa el formato del email.";
const status = !touched || value === "" ? "hint" : isValid ? "ok" : "error";
return (
<label className="field">
<span>Email</span>
<input
type="email"
value={value}
onChange={(e) => setValue(e.target.value)}
onBlur={() => setTouched(true)}
aria-invalid={status === "error"}
aria-describedby="email-help"
/>
<small id="email-help" data-status={status} aria-live="polite">
{message}
</small>
</label>
);
}
Y el CSS base:
.field small {
display: block;
min-height: 1.25rem;
margin-top: 0.35rem;
}
Lo bueno de este patron es que la explicacion inicial ya ocupa el espacio final. El mensaje cambia, pero no empuja nada. Parece poca cosa, aunque en formularios con varios pasos la diferencia se siente muchisimo.
Accesibilidad que no estorba
Hay un error frecuente en equipos frontend: querer ser accesibles agregando ruido visual. No hace falta. Una ayuda persistente, corta y bien ubicada hace mas por accesibilidad que diez animaciones de error.
Yo suelo revisar cuatro cosas:
- El mensaje esta asociado con
aria-describedby. -
aria-invalidsolo aparece cuando realmente hay error. - El color no es la unica señal.
- El texto del error explica que corregir, no solo que algo falló.
Si ademas estas afinando correos de onboarding en SaaS, conviene que el campo de email no robe atención innecesaria. El formulario no deberia competir con el resto del flujo por un detalle de presentacion que era evitable.
Como medir si el cambio de verdad ayuda
Mi forma favorita es bastante pragmatica:
- Grabo una sesion corta antes y despues.
- Mido cuantos errores de email se corrigen al primer intento.
- Reviso si baja el tiempo hasta submit en mobile.
- Confirmo que no aparezcan shifts visibles al cambiar de estado.
Si tienes telemetria de frontend, puedes registrar blur, error_shown y submit_success por campo. No hace falta volverse loco con cien eventos. Con tres señales ya puedes ver si el cambio mejora claridad o solo se ve mas prolijo.
Tambien sirve probar con inputs menos limpios: copiar y pegar, autocompletado, teclados de Android, y emails temporales usados en testing. Muchas veces el bug no esta en la regex; esta en el momento exacto en que decidimos interrumpir al usuario.
Preguntas rapidas
Debo validar en cada tecla
Solo si el feedback no castiga. Para email, prefiero esperar a blur o a una pausa corta. Validar demasiado pronto se siente ansioso, y eso el usuario lo nota enseguida.
Uso display: none cuando no hay error
Prefiero no hacerlo si eso elimina el espacio reservado. Puedes ocultar visualmente el cambio con opacidad o simplemente mostrar una ayuda neutra al inicio.
Esto mejora conversion
No siempre por si solo, pero si elimina una fricción muy facil de evitar. En varios equipos he visto que mejora la sensacion general del formulario, y esa comodidadad luego ayuda a que mas gente termine el paso.
Un campo de email estable no es una gran feature. Pero si es una de esas decisiones pequeñas que hacen que un formulario se vea mejor, se lea mejor y falle menos. Y en frontend, ese tipo de detalle casi siempre paga.
Top comments (0)