OTP Input
A segmented one-time-code input for verification and 2FA. Controlled —
onChange emits the code string (never an
event), and onComplete fires when it’s full. Paste a whole
code and every slot fills; typing auto-advances, backspace steps back.
Drops straight into Form.
6-digit code
Type or paste. onComplete fires once all six slots are
filled — wire it to your verify call.
Enter the 6-digit code (try pasting "123456")
import { useState } from "react";
import { OTPInput } from "@usevyre/react";
const [code, setCode] = useState("");
<OTPInput
value={code}
onChange={setCode}
onComplete={(c) => verify(c)}
autoFocus
/> <script setup>
import { ref } from "vue";
import { OTPInput } from "@usevyre/vue";
const code = ref("");
function verify(c) { /* ... */ }
</script>
<template>
<OTPInput
v-model="code"
@complete="verify"
autofocus
/>
</template> Masked PIN
mask renders dots (like a password); combine with
length and size for a short PIN.
Masked 4-digit PIN
import { useState } from "react";
import { OTPInput } from "@usevyre/react";
const [pin, setPin] = useState("");
<OTPInput value={pin} onChange={setPin} length={4} mask size="lg" /> <script setup>
import { ref } from "vue";
import { OTPInput } from "@usevyre/vue";
const pin = ref("");
</script>
<template>
<OTPInput v-model="pin" :length="4" mask size="lg" />
</template> Props
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled value. Omit for uncontrolled. |
defaultValue | string | "" | Initial value when uncontrolled. |
onChange | (value: string) => void | — | Emits the combined code string. NOT an event. |
onComplete | (value: string) => void | — | Fires once when every slot is filled. |
length | number | 6 | Number of slots. |
type | "numeric" | "alphanumeric" | "numeric" | Accepted characters. |
mask | boolean | false | Render dots instead of characters. |
size | "sm" | "md" | "lg" | "md" | Slot size. |
disabled | boolean | false | Disable all slots. |
autoFocus | boolean | false | Focus the first slot on mount (Vue: autofocus). |
Emits a string, not an event. Like the other useVyre
inputs,
onChange gives you the value directly — so it works in
FormField with no glue.
Valid props
| Prop | Values | Default |
|---|---|---|
type | "numeric"|"alphanumeric" | numeric |
size | "sm"|"md"|"lg" | md |
mask | true|false | false |
disabled | true|false | false |
autoFocus | true|false | false |
Common AI mistakes
- onChange={(e) => set(e.target.value)}→ onChange={(value) => setCode(value)}
- Six separate <Input> boxes wired by hand→ Use <OTPInput length={6} value onChange />
- Reading completion by comparing length yourself→ Use onComplete={(code) => verify(code)}
- type="password" to hide digits→ Use mask (type stays numeric/alphanumeric)
Quick examples
2FA code with verify on complete
const [code, setCode] = useState("");
<OTPInput
value={code}
onChange={setCode}
onComplete={(c) => verify(c)}
autoFocus
/>Inside a Form
<FormField name="otp" label="Verification code"
rules={{ required: true, minLength: 6 }}>
<OTPInput length={6} />
</FormField>