RHFOTPInput
OTP (One-Time Password) input component integrated with React Hook Form
You are reading the v1 docs. v2 renamed several props and replaced GeckoUIPortal with GeckoUIProvider. Read this page in v2.
Live examples are only rendered in the v2 docs.
RHFOTPInput
An OTP (One-Time Password) input component integrated with React Hook Form that provides a segmented input field for entering verification codes. Each digit is displayed in a separate box with automatic focus management and keyboard navigation. Automatically displays error states with a red border when validation fails.
Installation
import { RHFOTPInput } from '@geckoui/geckoui';Basic Usage
import { useForm, FormProvider } from 'react-hook-form';
import { RHFOTPInput } from '@geckoui/geckoui';
function Example() {
const methods = useForm({
defaultValues: {
basicOtp: ''
}
});
return (
<FormProvider {...methods}>
<RHFOTPInput name="basicOtp" />
</FormProvider>
);
}Props API
Extends all props from base OTPInput component plus:
| Prop | Type | Default | Description |
|---|---|---|---|
name | string | - | Field name (required) |
control | Control | Auto-injected | Optional: Pass explicitly for nested forms or custom form context |
rules | RegisterOptions | - | Inline validation rules |
length | number | 6 | Number of OTP input fields to display |
numberOnly | boolean | true | If true, only numeric input is allowed |
onOTPComplete | (value: string) => void | - | Callback when all OTP fields are filled |
className | string | - | Wrapper div classname |
inputClassName | string | - | Individual input field classname |
aspectRatio | string | number | 0.94 | Aspect ratio for each input box |
disabled | boolean | false | Disable all input fields |
Examples
With Validation (Zod)
import { useForm, FormProvider } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { RHFOTPInput, RHFInputGroup } from '@geckoui/geckoui';
const schema = z.object({
validationCode: z.string().length(6, 'OTP must be exactly 6 digits').regex(/^\d+$/, 'OTP must contain only numbers')
});
function Example() {
const methods = useForm({
resolver: zodResolver(schema),
mode: 'onBlur',
defaultValues: { validationCode: '' }
});
return (
<FormProvider {...methods}>
<RHFInputGroup label="Verification Code" required>
<RHFOTPInput name="validationCode" />
</RHFInputGroup>
</FormProvider>
);
}Six Digit Code
<RHFOTPInput name="sixDigitPin" length={6} />Four Digit PIN
<RHFOTPInput name="fourDigitPin" length={4} />Alphanumeric Code
const schema = z.object({
activationCode: z.string().length(8, 'Activation code must be exactly 8 characters')
});
<RHFInputGroup label="Activation Code" required>
<RHFOTPInput name="activationCode" length={8} numberOnly={false} />
</RHFInputGroup>Disabled State
<RHFOTPInput name="disabledOtp" disabled />Complete Form Example
import { useForm, FormProvider } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { RHFOTPInput, RHFInputGroup, Button } from '@geckoui/geckoui';
const schema = z.object({
twoFactorCode: z.string().length(6, 'Code must be exactly 6 digits').regex(/^\d+$/, 'Code must contain only numbers')
});
function TwoFactorForm() {
const methods = useForm({
resolver: zodResolver(schema),
mode: 'onBlur',
defaultValues: {
twoFactorCode: ''
}
});
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(console.log)}>
<RHFInputGroup label="Two-Factor Authentication Code" required>
<RHFOTPInput
name="twoFactorCode"
onOTPComplete={(value) => {
console.log('OTP completed:', value);
}}
/>
</RHFInputGroup>
<Button type="submit">Verify Code</Button>
</form>
</FormProvider>
);
}Inline Rules Validation
For simple validation, use the rules prop:
<RHFOTPInput
name="otp"
rules={{
required: 'OTP is required',
minLength: { value: 6, message: 'OTP must be 6 digits' }
}}
/>For complex forms, we recommend using a schema resolver (Zod, Yup) instead.
Length Configuration
Configure the number of OTP input fields using the length prop:
<RHFOTPInput name="pin" length={4} />
<RHFOTPInput name="code" length={6} />
<RHFOTPInput name="activationKey" length={8} />By default, length is set to 6 digits.
Input Mode
Control whether users can enter only numbers or alphanumeric characters:
<RHFOTPInput name="numericCode" numberOnly={true} />
<RHFOTPInput name="alphanumericCode" numberOnly={false} />By default, numberOnly is true, restricting input to numeric characters only.
OTP Completion Callback
Use onOTPComplete to perform actions when all OTP fields are filled:
<RHFOTPInput
name="otp"
onOTPComplete={(value) => {
console.log('OTP entered:', value);
verifyCode(value);
}}
/>This callback is triggered automatically when the user completes entering all digits.
Error States
RHFOTPInput automatically displays error states with:
- Red border via
data-errorattribute on the root element whenfieldState.errorexists - Individual input fields inherit error styling
.GeckoUIRHFOTPInput[data-error] {
border-color: red;
}Use RHFInputGroup component for label + input + error layout:
<RHFInputGroup label="Verification Code" required>
<RHFOTPInput name="code" />
</RHFInputGroup>Or combine with RHFError component manually:
<RHFOTPInput name="code" />
<RHFError name="code" />Tip: Use mode: 'onBlur' in useForm to validate on blur for better UX:
const methods = useForm({
resolver: zodResolver(schema),
mode: 'onBlur'
});Validation Patterns
Common Zod validation patterns for OTP inputs:
const schema = z.object({
sixDigitCode: z.string()
.length(6, 'Code must be exactly 6 digits')
.regex(/^\d+$/, 'Code must contain only numbers'),
fourDigitPin: z.string()
.length(4, 'PIN must be exactly 4 digits')
.regex(/^\d+$/, 'PIN must contain only numbers'),
alphanumericCode: z.string()
.length(8, 'Code must be exactly 8 characters')
.regex(/^[A-Za-z0-9]+$/, 'Code must be alphanumeric')
});Accessibility
- Automatic focus management between input fields
- Keyboard navigation support (arrow keys, backspace, delete)
- Proper ARIA attributes for error states
- Tab navigation support with smart focus handling
- Input mode hints for mobile keyboards (numeric vs text)
- Screen reader compatible
Keyboard Navigation
- Numbers/Letters: Enter value and auto-advance to next field
- Backspace/Delete: Remove current value and move to previous field
- Tab: Navigate to next unfilled field
- Enter: Submit form when last field is filled
- Paste: Automatically distribute pasted content across fields
Related Components
- OTPInput - Base OTP input component
- RHFInput - Text input with RHF
- RHFInputGroup - Label + input + error layout
- RHFError - Error message display