Component · OTP Input

OTP Input

Campo de 6 dígitos para los códigos de verificación que MiCapi envía por correo y celular — en el registro y para confirmar operaciones sensibles. Auto-avance, paste, autofill de SMS en Android. Construido con tokens del DS: celdas mono, radius-md, focus-ring y motion estándar.

6 dígitos · mono 6 estados autofill SMS reenvío + lockout
Anatomía

6 celdas cuadradas de 44×52dp, gap de 8dp, centradas. La celda activa eleva el borde a 2dp primary con glow del focus-ring; el dígito va en JetBrains Mono a 24dp.

4
8
celda llena
celda activa · caret
Celda
44 × 52dp
Gap
8dp · space-2
Radio
10dp · radius-md
Dígito
24dp · mono
Borde reposo
1dp · neutral-300
Borde activo
2dp · primary-500
Fondo
surface
Focus ring
4px · 12% primary
Estados

Seis estados cubren todo el ciclo de entrada y validación.

Empty
a · reposo
Ingresa el código de 6 dígitos
6 celdas vacías, primera activa con caret. El teclado numérico se abre automáticamente al entrar a la pantalla.
Partial
b · escribiendo
4
8
2
 
Auto-avance: al escribir un dígito el foco salta a la siguiente celda. Backspace en celda vacía retrocede y borra la anterior.
Complete
c · listo
4
8
2
9
1
5
Validando automáticamente…
6 dígitos completos. Dispara HapticFeedback.lightImpact() y valida sin necesidad de un botón "Confirmar".
Error
d · incorrecto
4
8
2
9
1
0
Código incorrecto. Intenta de nuevo.
Las 6 celdas en borde danger + shake sutil (translateX, duration-fast — opcional). Tras el shake, las celdas se limpian y vuelve a Empty.
Success
e · validado
4
8
2
9
1
5
Verificado
Borde success breve antes de avanzar a la siguiente pantalla. Animar es opcional — la transición de página ya comunica el éxito.
Disabled
f · validando
4
8
2
9
1
5
 Procesando…
Durante la validación en curso: celdas en gris, no editables, spinner pequeño. Previene doble envío mientras la red responde.
Reenvío y bloqueo

El reenvío arranca con countdown de 60s; tras 3 intentos fallidos, bloqueo temporal de 10 minutos.

Reenvío · countdown activo (primeros 60s)
4
8
¿No recibiste el código? Reenviar en 0:45
Reenvío · habilitado (tras 60s)
¿No recibiste el código? Reenviar

Demasiados intentos. Espera 10 minutos.

Tras 3 códigos incorrectos, el input se bloquea 10 minutos como medida de seguridad. El campo queda deshabilitado y el reenvío oculto hasta que expire el bloqueo.

Motion

Mínima por diseño: el input no debe sentirse "animado", debe sentirse instantáneo.

Auto-avance instantáneo

El salto entre celdas no se anima — es feedback de input directo. Cualquier transición lo haría sentir lento.

Haptic al completar

HapticFeedback.lightImpact() al ingresar el 6º dígito — confirma táctilmente que el código está completo y se va a validar.

Error shake — opcional

Shake sutil (translateX, duration-fast) al fallar. Sujeto a prueba de UX: refuerza el error visual pero puede sentirse excesivo en uso repetido. No es regla fija.

Reduced motion

Con disableAnimationsOf(context) el shake se elimina y el error se comunica solo con color + mensaje. El haptic se mantiene — es táctil, no visual.

Modo oscuro

Empty · partial · complete · error sobre superficie oscura.

Empty
Ingresa el código de 6 dígitos
Partial
4
8
2
 
Complete
4
8
2
9
1
5
Validando automáticamente…
Error
4
8
2
9
1
0
Código incorrecto. Intenta de nuevo.
Flutter notes

Implementación

Pinput
Paquete recomendado — maneja celdas, auto-avance, paste y temas en un widget. Mapear defaultPinTheme / focusedPinTheme / errorPinTheme a los tokens del DS.
6× TextField + FocusNode
Alternativa manual: un TextField por celda con su FocusNode; en onChanged avanzar con FocusScope.requestFocus, en backspace retroceder.
autofillHints
autofillHints: [AutofillHints.oneTimeCode] en cada campo habilita el autofill del OTP desde SMS en Android. Pinput lo soporta nativo.
SmsAutoFill
Para lectura automática del SMS entrante (sin que el usuario salga de la app), integrar sms_autofill con el hash de la app.
HapticFeedback
lightImpact() al completar los 6 dígitos. Error haptic opcional, sujeto a prueba.
Validación
Disparar al completar (sin botón). Mostrar estado disabled + spinner mientras responde la red; limpiar celdas tras error.