# 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.
