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 six numeric inputs and adds nullable, digits:6, and numeric validation. Add required() to reject blank values.

Example
php
use InertiaUI\Forms\Fields\OtpInput;

OtpInput::make('code');

Length ​

Change the number of input boxes:

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

The configured length drives the validation rule. Numeric mode uses Laravel's digits rule. Alphanumeric mode and numeric(false) use the string size rule.

Input Type ​

Numeric (Default) ​

Allow only digits 0-9 in Vue and React and add the numeric validation rule. The managed length rule is digits.

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

This is the default. Use numeric() to switch back from alphanumeric(), or numeric(false) to permit unrestricted characters. Unrestricted fields use string and size, so arrays are still rejected.

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 the length rule becomes 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.