@kunlexze1/react-native-otp-timer
v1.0.0
Published
OTP input component + countdown timer hook for React Native (using react-native-otp-entry)
Maintainers
Readme
react-native-otp-timer
A comprehensive React Native OTP input component with built-in countdown timer functionality, built on top of react-native-otp-entry.
Features
- 🔄 Auto Restart: Built-in restart button when timer expires
- 🎯 Complete OTP Input: All props from
react-native-otp-entryexposed - ⏰ Built-in Timer: Countdown timer with customizable duration
- 🎨 Fully Customizable: Timer styling, position, and formatting
- 📱 Background Support: Handles app state changes correctly
- 🔒 TypeScript: Full TypeScript support with proper types
- 🪝 Flexible Hooks: Use timer independently or with OTP component
- ♿ Accessible: Maintains accessibility features from base component
Installation
npm install react-native-otp-timer react-native-otp-entry
# or
yarn add react-native-otp-timer react-native-otp-entryQuick Start
import React from 'react';
import { OtpWithTimer } from 'react-native-otp-timer';
export default function App() {
const handleOtpFilled = (otp: string) => {
console.log('OTP entered:', otp);
};
const handleResendOtp = async () => {
// Call your API to resend OTP
console.log('Resending OTP...');
// await api.resendOtp();
};
return (
<OtpWithTimer
numberOfDigits={6}
timerDuration={120} // 2 minutes
onFilled={handleOtpFilled}
onTimerExpire={() => console.log('Timer expired!')}
onRestartTimer={handleResendOtp}
showRestartButton={true}
restartButtonText="Resend OTP"
/>
);
}API Reference
OtpWithTimer Props
Timer Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| timerDuration | number | 60 | Timer duration in seconds |
| timerStyle | TextStyle | - | Custom styling for timer text |
| timerFormatter | (time: string) => string | - | Custom timer display formatter |
| showTimer | boolean | true | Show/hide the timer |
| timerPosition | 'top' \| 'bottom' | 'top' | Timer position relative to OTP |
| autoStartTimer | boolean | true | Auto-start timer on mount |
| onTimerExpire | () => void | - | Called when timer expires |
| onTimerStart | () => void | - | Called when timer starts |
| onTimerReset | () => void | - | Called when timer resets |
| onRestartTimer | () => void | - | Called when timer restarts |
| showRestartButton | boolean | true | Show restart button when expired |
| restartButtonText | string | 'Resend OTP' | Custom restart button text |
| restartButtonStyle | TextStyle | - | Custom restart button styling |
OTP Props (from react-native-otp-entry)
All props from react-native-otp-entry are supported:
| Prop | Type | Description |
|------|------|-------------|
| numberOfDigits | number | Number of OTP digits |
| onFilled | (text: string) => void | Called when OTP is complete |
| focusColor | string | Focus color for inputs |
| theme | object | Styling theme object |
| ... and many more | | See react-native-otp-entry docs |
Hooks
useTimer
Standalone timer hook for custom implementations:
import { useTimer } from 'react-native-otp-timer';
function CustomTimer() {
const { timeLeft, hasTimeout, startTimer, resetOtpTimer } = useTimer(60);
return (
<View>
<Text>{timeLeft}</Text>
<Button title="Reset" onPress={resetOtpTimer} />
</View>
);
}useOtpTimer
Enhanced timer hook with additional utilities:
import { useOtpTimer } from 'react-native-otp-timer';
function EnhancedTimer() {
const { timeLeft, hasTimeout, startTimer, resetTimer, restartTimer } = useOtpTimer(120);
const handleResend = () => {
restartTimer(); // Resets and starts the timer
// Call your resend API here
};
return (
<View>
<Text>{timeLeft}</Text>
{hasTimeout && (
<Button title="Resend OTP" onPress={handleResend} />
)}
</View>
);
}Advanced Usage
Timer Restart Options
1. Built-in Restart Button
<OtpWithTimer
numberOfDigits={6}
timerDuration={60}
showRestartButton={true}
restartButtonText="Get New Code"
restartButtonStyle={{ color: '#007AFF', fontWeight: 'bold' }}
onRestartTimer={() => {
console.log('Resending OTP...');
// Call your resend OTP API
}}
/>2. Programmatic Restart
import { useOtpTimer } from 'react-native-otp-timer';
function CustomOtpScreen() {
const { restartTimer, hasTimeout, timeLeft } = useOtpTimer(60);
const handleManualResend = async () => {
try {
await resendOtpApi();
restartTimer(); // Restart the timer after successful API call
} catch (error) {
console.error('Failed to resend OTP');
}
};
return (
<View>
<OtpWithTimer
numberOfDigits={6}
showRestartButton={false} // Hide built-in button
/>
<Text>Timer: {timeLeft}</Text>
{hasTimeout && (
<Button title="Resend Code" onPress={handleManualResend} />
)}
</View>
);
}Custom Timer Formatting
<OtpWithTimer
numberOfDigits={4}
timerDuration={300}
timerFormatter={(time) => `Expires in: ${time}`}
timerStyle={{ color: 'red', fontSize: 18 }}
/>Timer Position Control
<OtpWithTimer
numberOfDigits={6}
timerPosition="bottom"
showTimer={true}
/>Complete Example
import React, { useState } from 'react';
import { View, StyleSheet, Alert } from 'react-native';
import { OtpWithTimer } from 'react-native-otp-timer';
export default function OtpVerificationScreen() {
const [isLoading, setIsLoading] = useState(false);
const handleOtpComplete = async (otp: string) => {
setIsLoading(true);
try {
const response = await verifyOtp(otp);
if (response.success) {
// Navigate to next screen
Alert.alert('Success', 'OTP verified successfully!');
}
} catch (error) {
Alert.alert('Error', 'Invalid OTP. Please try again.');
} finally {
setIsLoading(false);
}
};
const handleResendOtp = async () => {
try {
await resendOtpApi();
Alert.alert('Success', 'New OTP sent to your phone!');
} catch (error) {
Alert.alert('Error', 'Failed to resend OTP. Please try again.');
}
};
return (
<View style={styles.container}>
<OtpWithTimer
numberOfDigits={6}
timerDuration={300} // 5 minutes
focusColor="#007AFF"
type="numeric"
secureTextEntry={false}
disabled={isLoading}
autoStartTimer={true}
showRestartButton={true}
restartButtonText="Didn't receive code? Resend"
timerPosition="bottom"
containerStyle={styles.otpContainer}
timerStyle={styles.timerText}
restartButtonStyle={styles.resendButton}
theme={{
pinCodeContainerStyle: styles.pinContainer,
focusedPinCodeContainerStyle: styles.focusedPin,
filledPinCodeContainerStyle: styles.filledPin,
pinCodeTextStyle: styles.pinText,
}}
onFilled={handleOtpComplete}
onTimerExpire={() => Alert.alert('Timeout', 'OTP has expired')}
onRestartTimer={handleResendOtp}
textInputProps={{
accessibilityLabel: 'OTP digit input',
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 20,
},
otpContainer: {
marginVertical: 20,
},
timerText: {
fontSize: 16,
color: '#666',
fontWeight: '500',
},
resendButton: {
fontSize: 14,
color: '#007AFF',
fontWeight: '600',
},
pinContainer: {
borderWidth: 2,
borderColor: '#E0E0E0',
borderRadius: 12,
width: 50,
height: 60,
},
focusedPin: {
borderColor: '#007AFF',
backgroundColor: '#F0F8FF',
},
filledPin: {
borderColor: '#4CAF50',
backgroundColor: '#F0FFF0',
},
pinText: {
fontSize: 20,
fontWeight: '600',
},
});Requirements
- React Native >= 0.71
- React >= 17
- react-native-otp-entry >= 1.8.0
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Issues & Support
If you encounter any issues or have questions:
- Check the GitHub Issues
- Create a new issue with detailed information
- Provide React Native version, device information, and code examples
Changelog
v1.0.0
- Initial release
- Complete OTP input with timer functionality
- Built-in restart capabilities
- Full TypeScript support
- Background app state handling
Support
If you find this package helpful, please consider:
- ⭐ Starring the repository
- 🐛 Reporting bugs
- 💡 Suggesting new features
- 📖 Improving documentation
Made with ❤️ for the React Native community
