Skip to content
Devix Open Source
UI component v1.0.0 MIT Alpha

OTP Input

One-time code input with paste, autofill from SMS and accessibility built in.

npm install @devix-labs/otp-input
Vanilla JS React Vue Svelte Angular
Enter the code Open

Real inputs, so a password manager can fill them; autocomplete="one-time-code" for iOS; the WebOTP API for Chrome on Android, which hands the code over without the person leaving the page; and when a manager drops the whole code into the first box, it is spread across the rest. Paste a whole SMS anywhere in the group and only the digits land. A labelled group with “Digit 3 of 6” on each box and a live region that follows along. 3 KB, no dependencies, and the same behaviour in React, Vue, Svelte or a plain page.

What you get

Autofill that works

autocomplete="one-time-code" for iOS and password managers, the WebOTP API for Chrome on Android — the two platforms every competing library has open issues about.

Real inputs

Not boxes drawn over a hidden field. A password manager sees something it can fill, and when it fills all six characters into the first box they spread across the rest.

Paste the whole message

“Your verification code is 123-456. Do not share it.” becomes 123456, pasted anywhere in the group — including from an Arabic SMS.

reject(), for the second attempt

Marks every box, announces the reason to a screen reader and puts the cursor back at the start — what every verification screen needs and none of them ships.

Readable by a screen reader

A labelled group, “Digit 3 of 6” on each box, and a live region saying “3 of 6 entered” then “Code complete”.

3 KB, any framework

One DOM core with React, Vue, Svelte and a web component over it. The most used alternative is React-only at 22 million downloads a week.

OTP Input — overview

Why it exists

Twenty-two million downloads a week go to a React-only package whose most-reacted open issue is about its own core approach, and the second most used cannot autofill from an SMS in Chrome. Neither works in a Vue or a plain project.

What it does differently

  • Autofill on every platform people complain about: autocomplete="one-time-code" for iOS and password managers, the WebOTP API for Chrome on Android, and spreading a whole code out when a manager drops it into the first box.
  • Real inputs, not boxes drawn over a hidden field.
  • One core, four wrappers, so React, Vue, Svelte and a plain page behave identically.
  • reject(), because every verification screen needs to mark a failed attempt, say so out loud and start again.
  • 3.0 kB.

Not in 1.0

A built-in resend countdown, and reading the code from a clipboard-watching background listener. Both are the application's job, and the second is a privacy problem.

How it compares

Questions

Why does SMS autofill fail in other libraries?

Two reasons. On iOS the first box must carry autocomplete="one-time-code", which several libraries put on the wrong element or on all of them. On Android Chrome the reliable route is the WebOTP API, which almost nobody implements — react-otp-input has had open issues about both since 2023. This does both.

What happens when 1Password fills the whole code into one box?

It is spread across the boxes. That case has its own browser test, because it is what password managers actually do and what breaks most implementations.

Does the WebOTP API need anything from my server?

Only that the SMS ends with an origin line — a blank line, then @example.com #123456. Without it the browser will not offer the code; with it, Chrome on Android fills the field without the person leaving the page.

Can I use it for a PIN rather than a code?

Yes: mask: true renders password boxes, and separators let you draw 123–456 without the separator ever appearing in the value.

Does it work in a form without JavaScript of my own?

Yes. The input you point at becomes the hidden field carrying the whole code under its existing name, and it fires input and change, so a plain form or a framework binding works untouched.