He visto un fallo bastante comun en formularios de signup: el input de email "ayuda" demasiado pronto. El usuario escribe tres letras, aparece un error rojo, cambia el layout, se mueve el foco visual y todo se siente mas torpe de lo que deberia. En productos reales eso no solo molesta, tambien baja la tasa de finalizacion y complica las pruebas.
En equipos frontend suelo separar tres cosas: escritura, validacion y anuncio. Parece un detalle pequeno, pero cambia bastante la experiencia. Si ademas haces pruebas con cuentas de QA o con un servicio de correo desechable, conviene que el formulario no dispare chequeos caros en cada tecla porque luego nadie sabe si el retraso viene del cliente, del API o del inbox de prueba.
Si te sirvieron ideas previas sobre jobs de email con contexto estable o sobre aislar correos automatizados con trazabilidad, aqui va la version enfocada en el input y el feedback visual.
Por que validar demasiado pronto rompe la experiencia
Cuando un campo de email valida en cada onChange, suelen aparecer tres problemas:
- re-renderes innecesarios en formularios con varios campos
- mensajes de error antes de que exista una intencion completa
- anuncios repetidos para lectores de pantalla
Eso se nota bastante en mobile, donde el teclado tapa media pantalla y cualquier salto visual se siente peor. Segun NN/g, los errores funcionan mejor cuando son claros, oportunos y faciles de corregir. La palabra importante ahi es "oportunos". No cada 120 ms, no en mitad de una direccion a medio escribir.
Tambien he visto equipos persiguiendo bugs con nombres raros como temp org mail o fake e mail com en datos de prueba. Muchas veces no es que el usuario o QA usen cadenas raras, es que el formulario mezcla feedback de formato con feedback de disponibilidad y todo queda medio confuso.
La regla: separar escritura, chequeo y anuncio
La regla que mejor me funciona es simple:
- Mientras la persona escribe, solo guardo el valor.
- Al perder foco, hago validacion de formato.
- Solo despues de pasar formato lanzo chequeos async o disponibilidad.
- El mensaje accesible cambia pocas veces y con una prioridad clara.
No es una idea revolucionaria, pero si evita mucho ruido. Tambien hace mas facil medir rendimiento, por que sabes exactamente cuando empieza cada fase. En un par de productos vimos una baja visible en validaciones abortadas despues de mover la comprobacion async a blur; no fue magia, fue quitar trabajo inutil nomas.
Un patron de React que reduce ruido y re-renderes
En React prefiero un estado pequeno y explicito:
type EmailState =
| { phase: "idle"; value: string }
| { phase: "format-error"; value: string; message: string }
| { phase: "checking"; value: string }
| { phase: "ok"; value: string }
| { phase: "server-error"; value: string; message: string };
function isValidEmail(value: string) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
}
Y luego conecto eventos con responsabilidades distintas:
const [email, setEmail] = useState<EmailState>({ phase: "idle", value: "" });
function onChange(next: string) {
setEmail((current) => ({ phase: "idle", value: next || current.value }));
}
async function onBlur(value: string) {
if (!isValidEmail(value)) {
setEmail({ phase: "format-error", value, message: "Escribe un correo valido." });
return;
}
setEmail({ phase: "checking", value });
const res = await fetch(`/api/email-check?email=${encodeURIComponent(value)}`);
const data = await res.json();
setEmail(
data.ok
? { phase: "ok", value }
: { phase: "server-error", value, message: "No pudimos verificar este correo ahora." }
);
}
No es el unico patron posible, pero tiene una ventaja practica: cada fase comunica una sola cosa. Eso vuelve mas facil estilizar, testear y anunciar cambios via aria-live. Tambien evita la costumbre de meter cinco booleanos que se contradicen entre si, que pasa mas seguido de lo que nos gustaria admitir.
En UI suelo dejar el mensaje persistente debajo del campo para no mover el layout. Si el texto cambia, cambia el contenido, no la estructura. Parece un detalle menor, pero el formulario se siente mucho mas estable y un poquito mas humano.
Como conectar pruebas reales sin contaminar el flujo
Si tu equipo hace pruebas de onboarding, magic links o confirmacion de cuenta, este campo suele terminar conectado a un backend de verificacion o a una bandeja temporal. El error comun es usar el mismo trigger para todo: formato, disponibilidad, comprobacion remota y estado final. Ahi empiezan los tickets raros de "a veces tarda" y nadie sabe donde mirar.
Yo intento mantener este contrato:
- el cliente resuelve formato localmente
- la red solo valida cuando ya hay una direccion plausible
- QA puede intercambiar un generador de inbox sin cambiar el comportamiento visual
Eso importa tambien para rendimiento. web.dev explica bien como reducir trabajo en interacciones para bajar la latencia percibida. Si tu input dispara validaciones costosas por tecla, el problema no siempre aparece en Lighthouse, pero si aparece en personas reales, y eso vale mas.
Checklist rapido para revisar accesibilidad y rendimiento
Antes de dar por bueno un formulario de email, reviso esto:
- el campo no muestra error antes de tiempo
- el texto de ayuda y el error comparten una zona estable
-
aria-invalidsolo se activa cuando hay error real - la validacion remota tiene cancelacion o ignora respuestas viejas
- el spinner, si existe, no roba foco ni ocupa demasiado espacio
- las pruebas cubren teclado, lector de pantalla y latencia de red
No es una lista glamorosa, pero funciona. Y si algo falla, sabes mas rapido si fue CSS, estado, fetch o infraestructura. Ese orden ahorra horas, sinceramnte.
Q&A
Debo validar solo al enviar?
No siempre. Validar solo al enviar reduce ruido, pero puede llegar tarde para algunos flujos. Para email, blur suele ser un punto bastante bueno entre ayuda y paciencia.
Que hago con dominios corporativos o reglas especiales?
Primero separa formato basico de reglas de negocio. Si una empresa necesita dominios permitidos, eso va despues del formato correcto. Mezclar ambas cosas en un mismo mensaje queda confuso y aveces injusto para la persona usuaria.
Este patron sirve fuera de React?
Si. La idea central no depende del framework. Lo importante es separar fases, limitar trabajo por tecla y mantener estable el anuncio accesible. React solo hace que ese modelado sea comodo.
Top comments (0)