WebberUI

OTP Input

A segmented verification-code input — a single invisible input sits over the visual cells, with paste support, an error shake, and a success ripple that turns the cells green.

Loading preview…
npx shadcn@latest add https://webberui.com/r/otp-input.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

6
<OtpInput />

Installation

npx shadcn@latest add https://webberui.com/r/otp-input.json

The install also writes the --wb-duration-fast and --wb-ease-out CSS variables into your global stylesheet.

Usage

import { OTPInput } from "@/components/ui/otp-input";

<OTPInput
  onComplete={(code) => verify(code)}
  error={isError}
  success={isSuccess}
/>

When value is omitted, the component manages it internally; when you need to clear and start over after a failed verification, use controlled mode instead (value + onChange).

Props

PropTypeDefaultDescription
lengthnumber6Number of cells
valuestringControlled value; when omitted, the component manages it internally
onChange(value: string) => voidFires when the value changes
onComplete(code: string) => voidFires once length characters have been entered, returning the complete code
errorbooleanfalseError state: the whole row shakes on the x axis and the borders turn red
successbooleanfalseSuccess state: the cells ripple green in sequence
type'numeric' | 'alphanumeric''numeric'Allowed character type; alphanumeric upper-cases automatically
disabledbooleanfalseDisables input

Accessibility

It uses a "single invisible input + visual cells" pattern rather than N separate inputs:

  • Screen readers only ever see one standard text field (aria-label="驗證碼"), with no jumping between six fields; the visual cells are all aria-hidden
  • autocomplete="one-time-code": iOS/Android can autofill the code in one tap when the SMS arrives
  • Pasting a complete code works directly, with no need to distribute it cell by cell
  • Keyboard behaviour is entirely native input behaviour: Backspace deletes, and inputMode="numeric" brings up the numeric keypad on mobile
  • On error it sets aria-invalid, so assistive technology can tell the field's state

How it works

  • The active cell shows a breathing caret and a focus ring, and characters pop into the cell from scale 0.5 → 1
  • The success ripple staggers by 60ms per cell, turning the border and text green in sequence
  • When the user has "reduce motion" enabled at the system level, the shake and pop animations are disabled and characters and states appear directly

On this page