Skip to content

OTP Input

The OtpInput field renders a series of individual character inputs for one-time password (verification code) entry. It handles paste support and may auto-submit when all digits are filled.

Basic Usage

This renders 6 numeric inputs in the browser. Call numeric() and length() when you also want the matching Laravel validation rules.

Example
php
use InertiaUI\Forms\Fields\OtpInput;

OtpInput::make('code');

Length

Change the number of input boxes:

Example
php
OtpInput::make('code')->length(4);

Calling length() alone adds the matching string size validation rule. Combined with numeric(), it uses Laravel's digits rule so a six-digit value such as 123456 is validated by digit count rather than numeric magnitude.

Input Type

Numeric (Default)

Allow only digits 0-9 in Vue and React and add the numeric validation rule. With length() also configured, the managed length rule is digits.

php
OtpInput::make('code')->numeric();

The browser inputs are numeric by default, but the managed Laravel numeric rule is added only when you call numeric(). Call numeric(false) to permit unrestricted characters and remove the managed character rule.

Alphanumeric

Allow letters and digits in Vue and React and add the alpha_num validation rule instead. Punctuation is filtered before the value is submitted, and length() continues to use the string size rule.

php
OtpInput::make('verification')->alphanumeric();

For direct components, pass numeric={false} and alphanumeric in React, or :numeric="false" and alphanumeric in Vue.

Password Mode

Mask the entered characters with dots, just like a password field:

Example
php
OtpInput::make('pin')->password();

Autofocus

Focus the first input automatically when the page loads:

php
OtpInput::make('code')->autofocus();

Auto Submit

Automatically submit the form when all inputs are filled:

php
OtpInput::make('code')->autoSubmit();

This is especially useful for verification flows without a separate submit button.

Grouping and Separators

Separator

Add a visual separator between inputs. Common choices are a dash or a dot:

php
OtpInput::make('code')->separator('-');

Group Size

Split the inputs into groups. Combined with a separator, this creates the classic "3-3" or "4-2" verification code look:

Example
-
php
// 123-456
OtpInput::make('code')
    ->length(6)
    ->groupSize(3)
    ->separator('-');

Placeholder

Set a placeholder character for empty inputs:

php
OtpInput::make('code')->placeholder('·');

Web OTP

The Web OTP API lets the browser auto-fill verification codes received via SMS. It's enabled by default, starts when the field receives focus, and works on Chrome for Android.

Disable it if needed:

php
OtpInput::make('code')->webOtp(false);

Auto-Submitting Verification Code

php
OtpInput::make('verification_code')
    ->label('Verification Code')
    ->help('Enter the 6-digit code sent to your phone')
    ->length(6)
    ->numeric()
    ->groupSize(3)
    ->separator('-')
    ->autoSubmit()
    ->required();

OtpInput also supports the shared label, help text, disabled and required state, validation, visibility, and styling APIs covered in Validation, Conditional Visibility, Authorization, and Styling.

Using the Component Directly

For manual form rendering, pass serialized field props from Manual Usage. For standalone use, bind a string value directly.

vue
<script setup lang="ts">
import { OtpInput } from '@inertiaui/form-vue/components'
import { ref } from 'vue'

const backupCode = ref('')
const trackPaste = () => {}
</script>

<template>
    <OtpInput
        v-model="backupCode"
        id="backup-code"
        name="backup_code"
        label="Backup code"
        help="Enter the 8-character recovery code."
        :length="8"
        :numeric="false"
        alphanumeric
        password
        autofocus
        auto-submit
        separator="-"
        :group-size="4"
        placeholder="*"
        :web-otp="false"
        data-testid="backup-code"
        @paste="trackPaste"
    />
</template>
tsx
import { useState } from 'react'
import { OtpInput } from '@inertiaui/form-react/components'

export function BackupCodeField() {
    const [backupCode, setBackupCode] = useState('')
    const trackPaste = () => {}

    return (
        <OtpInput
            value={backupCode}
            onValueChange={setBackupCode}
            id="backup-code"
            name="backup_code"
            label="Backup code"
            help="Enter the 8-character recovery code."
            length={8}
            numeric={false}
            alphanumeric
            password
            autofocus
            autoSubmit
            separator="-"
            groupSize={4}
            placeholder="*"
            webOtp={false}
            data-testid="backup-code"
            onPaste={trackPaste}
        />
    )
}

Native attributes and listeners are forwarded to the underlying OTP inputs. See Native Attributes And Events.