Components
OTP Input

OTP Input Component

Installation

The OTP Input component is designed for secure verification code entry in mobile applications.

Installation Command
npx @nativecn/cli add input-otp

Basic Usage

Basic OTP Input

Different Lengths

OTP Input Lengths

Variants & States

OTP Input Variants

With Timer & Resend

OTP Input with Timer

Code expires in 120s
Resend code

Advanced Usage Example

Complete Verification Flow
import React, { useState } from 'react';
import { View, Alert } from 'react-native';
import { OTPInput } from '@nativecn/ui';
import { useColorScheme } from 'react-native';

export function VerificationScreen() {
  const [isVerifying, setIsVerifying] = useState(false);
  const colorScheme = useColorScheme();

  const handleComplete = async (code) => {
    setIsVerifying(true);
    try {
      // Verify the code with your API
      const response = await verifyCode(code);
      if (response.success) {
        Alert.alert('Success', 'Verification completed!');
      } else {
        throw new Error('Invalid code');
      }
    } catch (error) {
      Alert.alert('Error', error.message);
    } finally {
      setIsVerifying(false);
    }
  };

  const handleResend = async () => {
    try {
      await resendVerificationCode();
      Alert.alert('Success', 'New code sent!');
    } catch (error) {
      Alert.alert('Error', 'Failed to resend code');
    }
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
      <OTPInput
        length={6}
        mode={colorScheme}
        disabled={isVerifying}
        onComplete={handleComplete}
        onResend={handleResend}
        expiresIn={300}
        showExpiryTimer={true}
        resendCooldown={60}
        maxResendAttempts={3}
        keyboard="numeric"
        autoFocus={true}
        shouldAutoSubmit={true}
        shouldHandleClipboard={true}
      />
    </View>
  );
}

Reference

OTP Input Props
interface OTPInputProps {
  // Core functionality
  length?: number;
  value?: string;
  onChange?: (value: string) => void;
  onComplete?: (value: string) => void;

  // Appearance
  disabled?: boolean;
  autoFocus?: boolean;
  separator?: boolean | React.ReactNode;
  size?: 'sm' | 'md' | 'lg';
  mask?: boolean;
  keyboard?: 'default' | 'numeric' | 'email-address' | 'phone-pad';
  error?: boolean | string;
  className?: string;
  mode?: 'light' | 'dark';

  // Input validation
  validateChar?: (char: string, index: number) => boolean;
  allowedChars?: string | RegExp;

  // Auto-submission
  shouldAutoSubmit?: boolean;
  autoSubmitDelay?: number;

  // Timeout/Expiry
  expiresIn?: number;
  onExpire?: () => void;
  showExpiryTimer?: boolean;

  // Resend functionality
  onResend?: () => void;
  resendCooldown?: number;
  maxResendAttempts?: number;

  // Clipboard
  shouldHandleClipboard?: boolean;

  // Animation
  animate?: boolean;
  animationDuration?: number;

  // Accessibility
  ariaLabel?: string;
  errorAriaLabel?: string;

  // Testing
  testID?: string;
}