@bhojaniasgar/react-native-otp-input
Version:
A fully customizable, responsive OTP input component for React Native with autofill support
320 lines (242 loc) • 11.3 kB
Markdown
# @bhojaniasgar/react-native-otp-input
[](https://www.npmjs.com/package/@bhojaniasgar/react-native-otp-input)
[](https://opensource.org/licenses/MIT)
[](https://expo.dev)
A fully customizable, responsive OTP (One-Time Password) input component for React Native with autofill support for Android and iOS.
**✅ Works with Expo** | **✅ Works with React Native CLI**
## ✨ Features
- 🎨 **Fully Customizable** - Extensive styling options for every state (default, focused, filled, error)
- 📱 **Responsive** - Built-in responsive sizing without external dependencies
- 🔄 **Auto-fill Support** - Automatic clipboard detection on Android
- ⌨️ **Smart Keyboard Handling** - Intelligent focus management and keyboard interactions
- 🌍 **RTL Support** - Full support for right-to-left languages
- 📦 **TypeScript** - Complete type definitions included
- 🔒 **Secure Entry** - Support for masked/secure text entry
- ♿ **Accessible** - Built with accessibility in mind
- ✅ **Expo Compatible** - Works seamlessly with Expo and React Native CLI
## 📦 Installation
### npm
npx expo install @bhojaniasgar/react-native-otp-input
### For React Native CLI Projects
```bash
npm install @bhojaniasgar/react-native-otp-input
yarn add @bhojaniasgar/react-native-otp-input
pnpm add @bhojaniasgar/react-native-otp-input
bun add @bhojaniasgar/react-native-otp-input
```
### Third Party Dependency
```bash
# Expo
npx expo install @react-native-clipboard/clipboard
# React Native CLI
npm install @react-native-clipboard/clipboard
```
## 🚀 Quick Start
```tsx
import React, { useState } from 'react';
import { View } from 'react-native';
import { OtpInputView } from '@bhojaniasgar/react-native-otp-input';
function App() {
const [code, setCode] = useState('');
return (
<View style={{ padding: 20 }}>
<OtpInputView
pinCount={6}
code={code}
onCodeChanged={setCode}
onCodeFilled={(code) => {
console.log(`OTP is ${code}, you are good to go!`);
}}
autoFocusOnLoad
/>
</View>
);
}
```
## 🔄 Auto-Fill Support
### Clipboard Auto-Fill (Android)
Enable automatic OTP code detection from clipboard on Android devices:
```tsx
import { OtpInputView } from '@bhojaniasgar/react-native-otp-input';
<OtpInputView
pinCount={6}
code={code}
onCodeChanged={setCode}
onCodeFilled={(code) => console.log('Auto-filled:', code)}
autoFill={true} // Enable clipboard auto-detection
/>
```
**How it works:**
- When `autoFill` is enabled, the component monitors the clipboard for OTP codes
- Automatically detects numeric codes matching the `pinCount` length
- Works seamlessly on Android devices
- Provides better paste support and field management
- No manual intervention required - just copy the OTP and it auto-fills!
**Requirements:**
- `@react-native-clipboard/clipboard` must be installed (see Installation section)
- Only works on Android platform
- OTP code must be numeric and match the specified `pinCount`
### SMS Retriever API (Android)
For automatic SMS OTP detection using Android's SMS Retriever API:
```tsx
import React, { useEffect, useState } from 'react';
import { Platform } from 'react-native';
import {
OtpInputView,
getHash,
startOtpListener,
removeListener
} from '@bhojaniasgar/react-native-otp-input';
function App() {
const [code, setCode] = useState('');
useEffect(() => {
if (Platform.OS === 'android') {
// Get app hash for SMS format
// IMPORTANT: This hash is computed from your app's signing certificate
// and cannot be changed. Use this EXACT hash in your backend SMS.
getHash()
.then((hashes) => {
console.log('App Hash:', hashes);
// Use this hash in your backend SMS: <#> Your OTP is 123456 [hash]
// Example: <#> Your OTP is 123456 L1lD8GP/5Eo
})
.catch((error) => console.error('Error getting hash:', error));
// Start listening for OTP SMS
startOtpListener((message: string) => {
if (!message) return;
// Extract OTP from SMS message
const otp = /(\d{6})/g.exec(message);
if (otp && otp[1]) {
setCode(otp[1]);
}
});
// Cleanup listener on unmount
return () => removeListener();
}
}, []);
return (
<OtpInputView
pinCount={6}
code={code}
onCodeChanged={setCode}
onCodeFilled={(code) => console.log('OTP verified:', code)}
/>
);
}
```
**Available SMS Retriever API Functions:**
```tsx
import {
getHash, // Get app hash for SMS format
startOtpListener, // Start listening for OTP SMS
addListener, // Add custom listener
removeListener, // Remove all listeners
getOtp, // Request OTP (triggers SMS Retriever)
requestHint, // Request phone number hint
useOtpVerify, // React hook for OTP verification
} from '@bhojaniasgar/react-native-otp-input';
```
**Understanding App Hash:**
The app hash is computed from your app's package name and signing certificate. This hash **cannot be changed at runtime** - it's determined by Android based on your app's signature.
```tsx
import { getHash } from '@bhojaniasgar/react-native-otp-input';
// Get your app's computed hash
const hashes = await getHash();
console.log('App Hash:', hashes); // e.g., ['L1lD8GP/5Eo']
// IMPORTANT: Use this EXACT hash in your backend SMS messages
// The hash is computed from your app's signing certificate and cannot be changed
```
**SMS Format Requirements:**
- SMS must start with `<#>`
- Must contain your app hash at the end (exact match required)
- Example: `<#> Your OTP is 123456 L1lD8GP/5Eo`
**Security & Hash Validation:**
The Android SMS Retriever API validates the hash at the **system level**. Only SMS messages with the **exact matching hash** will be delivered to your app.
Examples:
- ✅ App hash: `L1lD8GP/5Eo` | SMS: `<#> Your OTP is 123456 L1lD8GP/5Eo` → **Works**
- ❌ App hash: `L1lD8GP/5Eo` | SMS: `<#> Your OTP is 123456 L1lD8GP/5Eo1wdf` → **Blocked by Android**
- ❌ App hash: `L1lD8GP/5Eo` | SMS: `<#> Your OTP is 123456 DIFFERENT` → **Blocked by Android**
**Important Notes:**
- The hash is tied to your app's signing certificate
- Debug builds and release builds may have different hashes (different certificates)
- You cannot override or change this hash - it's computed by Android
- Always use `getHash()` to get the correct hash for your SMS messages
**Note:** SMS Retriever API only works on Android. iOS users should use clipboard auto-fill or manual entry.
## 📖 Documentation
### Getting Started && Examples
- **[Installation & Setup](#-installation)** - Installation instructions
- **[Examples](./example/BareCli/src/examples/)** - Live code examples 💻
### Examples Include:
- 🎨 Custom styling and themes
- 📏 Size presets and variants
- 🔄 Auto-fill support (clipboard & SMS)
- ❌ Error state handling
- 🔒 Secure entry
- ⚙️ Advanced configurations
### Note
Expo Example Coming Soon!
## 📚 API Reference
### Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `pinCount` | `number` | `6` | Number of OTP digits |
| `code` | `string` | `undefined` | Controlled value for the OTP |
| `onCodeChanged` | `(code: string) => void` | `undefined` | Callback fired when any digit changes |
| `onCodeFilled` | `(code: string) => void` | `undefined` | Callback fired when all digits are filled |
| `autoFocusOnLoad` | `boolean` | `true` | Auto focus first input on mount |
| `autoFill` | `boolean` | `false` | Enable automatic OTP detection from clipboard (Android only) |
| `secureTextEntry` | `boolean` | `false` | Hide input text (secure entry) |
| `editable` | `boolean` | `true` | Enable/disable input editing |
| `clearInputs` | `boolean` | `false` | Clear all inputs when true |
| `keyboardType` | `KeyboardTypeOptions` | `'number-pad'` | Keyboard type for input |
| `keyboardAppearance` | `'default' \| 'dark' \| 'light'` | `'default'` | Keyboard appearance theme |
| `containerStyle` | `ViewStyle` | `undefined` | Style for the main container |
| `codeInputFieldStyle` | `TextStyle` | `undefined` | Style for input fields (default state) |
| `codeInputHighlightStyle` | `TextStyle` | `undefined` | Style for focused input field |
| `filledInputFieldStyle` | `TextStyle` | `undefined` | Style for filled input fields |
| `errorInputFieldStyle` | `TextStyle` | `undefined` | Style for error state |
| `size` | `'small' \| 'medium' \| 'large' \| 'custom'` | `'medium'` | Preset size for inputs |
| `inputSpacing` | `number` | `undefined` | Spacing between inputs (custom size) |
| `inputWidth` | `number` | `undefined` | Width of each input (custom size) |
| `inputHeight` | `number` | `undefined` | Height of each input (custom size) |
| `fontSize` | `number` | `undefined` | Font size for input text (custom size) |
| `borderRadius` | `number` | `undefined` | Border radius for inputs (custom size) |
| `placeholderCharacter` | `string` | `''` | Character to show in empty inputs |
| `placeholderTextColor` | `string` | `undefined` | Color for placeholder text |
| `selectionColor` | `string` | `'#000'` | Color for text selection and cursor |
| `error` | `boolean` | `false` | Show error state styling |
| `onFocus` | `(index: number) => void` | `undefined` | Callback when an input receives focus |
| `onBlur` | `(index: number) => void` | `undefined` | Callback when an input loses focus |
## 🎯 Size Presets
The component includes three built-in size presets:
| Size | Width | Height | Font Size | Spacing |
|------|-------|--------|-----------|---------|
| Small | 40px | 40px | 16px | 8px |
| Medium | 50px | 50px | 20px | 10px |
| Large | 60px | 60px | 24px | 12px |
All sizes are responsive and scale based on screen dimensions.
## 🔧 Running the Examples
Want to see the component in action? Check out our example apps:
- **[Expo Example](./example/expo)** - Modern Liquid Glass Design with Expo Router
- **[React Native CLI Example](./example/BareCLi)** - Traditional React Native setup
**[View Examples Documentation →](./example/EXAMPLES.md)**
## 🤝 Contributing
Contributions are welcome! We'd love your help making this package better.
**[Read the Contributing Guide →](./CONTRIBUTING.md)**
Quick steps:
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request
See [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guidelines.
## 📄 License
MIT © Asgar
## 🙏 Acknowledgments
- Inspired by the need for a fully customizable, dependency-free OTP input component
- Built with ❤️ for the React Native community
## 📞 Support
- 📧 Email: [im.bhojaniasgar@gmail.com](mailto:im.bhojaniasgar@gmail.com)
- 🐛 Issues: [GitHub Issues](https://github.com/bhojaniasgar/react-native-otp-input/issues)
---
Made with ❤️ by Asgar