OTP Input

Customizable OTP input system with multi-field inputs, paste handling, keyboard navigation, and password masking.

Usage

npm install @frjoy/otp

Live Demo 1: Basic OTP

Entered OTP: -

<Root onChange={setOtp} type="number" password>
  <Label>Enter OTP</Label>
  {[...Array(6)].map((_, i) => (
    <Input key={i} length={1} />
  ))}
</Root>

Live Demo 2: Alphanumeric OTP with Joiner

This example shows a referral-style OTP code joined with -.

Joined Code: -

<Root onChange={setOtp} type="text" joiner="-">
  <Label>Referral Code</Label>
  {[...Array(4)].map((_, i) => (
    <Input key={i} length={2} />
  ))}
</Root>

Props Reference

<Root />

  • onChange?: (otp: string) => void
  • type?: 'number' | 'text' | 'any'
  • password?: boolean
  • joiner?: string
  • pattern?: string

<Input />

  • length?: number
  • password?: boolean
  • Supports all native input props

<Label />

  • Automatically focuses first incomplete field
  • Accessible via aria-live

Interactive Playground

Experiment with different props and see the changes in real-time.

Quick Presets

Configuration

Live Preview

Output:
No input yet

Length: 0 characters

Expected total: 6 characters

Try these features:

  • • Paste complete codes - they'll auto-fill
  • • Use arrow keys to navigate between inputs
  • • Backspace deletes and moves to previous input
  • • Enter moves to next input field

Generated Code

<Root 
  onChange={setOtp}
>
  <Label>Enter Code</Label>
  <div className="flex gap-1">
    {[...Array(6)].map((_, i) => (
      <Input
        key={i}
        length={1}
        className={"min-w-12 px-3 py-2 border border-gray-300 dark:border-gray-700 rounded focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
      />
    ))}
  </div>
</Root>

Share this package

Want to improve this page? Create a Pull Request