- Added input-otp library to streamline OTP input functionality. - Refactored OtpInput component to utilize InputOTP for improved user experience and mobile SMS autofill. - Enhanced LoginOtpStep and VerificationStep components to handle OTP input errors and clear states effectively. - Updated global styles to include animations for OTP caret, improving visual feedback during input. - Made minor adjustments to LoginForm and OtpStep components for better error handling and user interaction.
77 lines
2.6 KiB
Markdown
77 lines
2.6 KiB
Markdown
# OTP Input Redesign: Replace Custom with shadcn InputOTP
|
|
|
|
**Date**: 2026-03-06
|
|
**Status**: Approved
|
|
|
|
## Problem
|
|
|
|
The custom `OtpInput` component (`components/molecules/OtpInput/OtpInput.tsx`) has fundamental issues:
|
|
|
|
- `onComplete` never fired on typing due to a JS bug (`!string.includes("")` is always false)
|
|
- Manual focus management across 6 separate `<input>` elements is fragile
|
|
- No mobile SMS autofill support
|
|
- No password manager detection
|
|
- Edge cases around paste, backspace, and focus are hard to maintain
|
|
|
|
## Decision
|
|
|
|
Replace the custom implementation with `input-otp` via shadcn/ui's InputOTP component (Approach A).
|
|
|
|
## Architecture
|
|
|
|
```
|
|
input-otp (npm)
|
|
-> components/ui/input-otp.tsx (shadcn primitives)
|
|
-> components/molecules/OtpInput/OtpInput.tsx (wrapper, same API)
|
|
-> LoginOtpStep, OtpStep, VerificationStep (no changes)
|
|
```
|
|
|
|
## Component API (unchanged)
|
|
|
|
```ts
|
|
interface OtpInputProps {
|
|
length?: number; // default 6
|
|
value: string;
|
|
onChange: (value: string) => void;
|
|
onComplete?: (value: string) => void;
|
|
disabled?: boolean;
|
|
error?: string;
|
|
autoFocus?: boolean; // default true
|
|
}
|
|
```
|
|
|
|
## Visual Design
|
|
|
|
- Stripe-style grouped layout: two groups of 3 slots separated by a dash
|
|
- Slots: `border-border` default, `border-primary` + ring on active, `border-danger` on error
|
|
- `bg-card`, `text-foreground`, rounded corners on group edges
|
|
- Disabled: `opacity-50 cursor-not-allowed`
|
|
- Blinking caret animation
|
|
|
|
## What Changes
|
|
|
|
| File | Action |
|
|
| --------------------------------------------- | --------------------------------- |
|
|
| `package.json` | Add `input-otp` dependency |
|
|
| `components/ui/input-otp.tsx` | New — shadcn generated primitives |
|
|
| `components/molecules/OtpInput/OtpInput.tsx` | Rewrite internals, keep API |
|
|
| `LoginOtpStep`, `OtpStep`, `VerificationStep` | No changes |
|
|
|
|
## What Gets Deleted
|
|
|
|
- `useOtpHandlers` hook (focus, paste, keydown management)
|
|
- `getInputBorderClass` helper
|
|
- All 6 individual `<input>` elements
|
|
|
|
## Error Handling
|
|
|
|
Consumer-level error handling (already implemented this session) remains unchanged:
|
|
|
|
- LoginOtpStep: catches errors, clears input, clears error on typing via `onClearError`
|
|
- OtpStep: catches errors, clears input, clears error on typing via `clearOtpError`
|
|
- VerificationStep: syncs machine error to local state, clears input and error on typing
|
|
|
|
## shadcn CLI Note
|
|
|
|
Generated file imports `cn` from `@/lib/utils`. Project has `cn` at `@/shared/utils`. Fix the import in the generated file after running the CLI.
|