react-native-textinput-kit
v1.0.0
Published
A comprehensive input component library for React Native featuring highly customizable TextInput, OTP inputs, and split field components.
Downloads
23
Maintainers
Readme
React Native TextInput Kit
A comprehensive input component library for React Native featuring highly customizable TextInput, OTP inputs, and split field components with tree-shaking support for optimal bundle size.
🎯 Features
- ✅ Tree-shakeable exports - Import only what you need for smaller bundles
- ✅ Three specialized components: TextInput, OTPInput, SplitInput
- ✅ Fully customizable styling for every element
- ✅ Built-in label, error, and helper text support
- ✅ Individual field labels for split inputs
- ✅ OTP with paste support and fixed backspace navigation
- ✅ TypeScript support with comprehensive type definitions
- ✅ Backward compatibility with legacy API
- ✅ Production ready with extensive validation
📦 Installation
npm install react-native-textinput-kitor
yarn add react-native-textinput-kit🚀 Quick Start
Tree-shakeable Imports (Recommended)
// Import only what you need - smaller bundle size
import { TextInput } from 'react-native-textinput-kit'; // ~15KB
import { OTPInput } from 'react-native-textinput-kit'; // ~25KB
import { SplitInput } from 'react-native-textinput-kit'; // ~20KB
// Multiple imports
import { TextInput, OTPInput } from 'react-native-textinput-kit'; // ~30KB totalLegacy Import (Backward Compatible)
// Imports everything - larger bundle (~50KB)
import CustomTextInput from 'react-native-textinput-kit';
// Usage with type prop
<CustomTextInput type="default" />
<CustomTextInput type="otp" />
<CustomTextInput type="split" />📖 Usage Examples
Regular Text Input
import React, { useState } from 'react';
import { View } from 'react-native';
import { TextInput } from 'react-native-textinput-kit';
const BasicExample = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
return (
<View style={{ padding: 20 }}>
<TextInput
label="Email Address"
placeholder="Enter your email"
value={email}
onChangeText={setEmail}
labelRequired
keyboardType="email-address"
error={email && !email.includes('@') ? 'Invalid email' : undefined}
helperText="We'll never share your email"
// Custom Styles
containerStyle={{ marginBottom: 20 }}
labelStyle={{ color: '#1F2937', fontWeight: '600' }}
inputContainerStyle={{
borderRadius: 12,
backgroundColor: '#F9FAFB',
borderWidth: 2,
}}
focusedInputContainerStyle={{
borderColor: '#10B981',
backgroundColor: '#FFFFFF',
}}
/>
<TextInput
label="Password"
placeholder="Enter your password"
value={password}
onChangeText={setPassword}
secureTextEntry
labelRequired
helperText="Minimum 8 characters"
containerStyle={{ marginBottom: 20 }}
/>
</View>
);
};OTP Input
import React, { useState } from 'react';
import { View, Alert } from 'react-native';
import { OTPInput } from 'react-native-textinput-kit';
const OTPExample = () => {
const [otp, setOtp] = useState('');
const handleOtpChange = (value: string) => {
setOtp(value);
// Auto-submit when OTP is complete
if (value.length === 6) {
Alert.alert('OTP Complete', `Entered: ${value}`);
}
};
return (
<View style={{ padding: 20 }}>
{/* 6-digit OTP with paste support */}
<OTPInput
label="Enter OTP"
otpLength={6}
onOtpChange={handleOtpChange}
helperText="Paste your 6-digit code or enter manually"
otpInputContainerStyle={{
backgroundColor: '#F9FAFB',
borderRadius: 12,
width: 50,
height: 60,
}}
otpFocusedInputContainerStyle={{
borderColor: '#10B981',
backgroundColor: '#ECFDF5',
}}
/>
{/* 4-digit PIN */}
<OTPInput
label="PIN Code"
otpLength={4}
onOtpChange={(pin) => console.log('PIN:', pin)}
secureTextEntry
helperText="Enter your 4-digit PIN"
otpInputContainerStyle={{
borderRadius: 30, // Circular
width: 60,
height: 60,
}}
/>
</View>
);
};Split Fields with Individual Labels
import React, { useState } from 'react';
import { View } from 'react-native';
import { SplitInput } from 'react-native-textinput-kit';
const SplitFieldsExample = () => {
const [nameValues, setNameValues] = useState({});
const [dateValues, setDateValues] = useState({});
const [addressValues, setAddressValues] = useState({});
return (
<View style={{ padding: 20 }}>
{/* Name fields with individual labels */}
<SplitInput
splitFields={[
{
key: 'firstName',
label: 'First Name',
labelRequired: true,
placeholder: 'Enter first name',
autoCapitalize: 'words',
},
{
key: 'lastName',
label: 'Last Name',
labelRequired: true,
placeholder: 'Enter last name',
autoCapitalize: 'words',
}
]}
splitValues={nameValues}
onSplitChange={setNameValues}
helperText="Both names are required"
containerStyle={{ marginBottom: 20 }}
/>
{/* Date with different flex ratios and individual labels */}
<SplitInput
label="Date of Birth" // Optional global label
splitFields={[
{
key: 'month',
label: 'Month',
placeholder: 'MM',
maxLength: 2,
flex: 1,
keyboardType: 'numeric'
},
{
key: 'day',
label: 'Day',
placeholder: 'DD',
maxLength: 2,
flex: 1,
keyboardType: 'numeric'
},
{
key: 'year',
label: 'Year',
placeholder: 'YYYY',
maxLength: 4,
flex: 2,
keyboardType: 'numeric'
}
]}
splitValues={dateValues}
onSplitChange={setDateValues}
splitSpacing={8}
containerStyle={{ marginBottom: 20 }}
/>
{/* Address with mixed field types */}
<SplitInput
splitFields={[
{
key: 'city',
label: 'City',
labelRequired: true,
placeholder: 'City',
flex: 2,
autoCapitalize: 'words'
},
{
key: 'state',
label: 'State',
placeholder: 'ST',
flex: 1,
autoCapitalize: 'characters',
maxLength: 2
},
{
key: 'zip',
label: 'ZIP',
placeholder: 'ZIP',
flex: 1,
keyboardType: 'numeric',
maxLength: 5
}
]}
splitValues={addressValues}
onSplitChange={setAddressValues}
splitSpacing={10}
/>
</View>
);
};📚 API Reference
TextInput Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| value | string | - | Input value |
| onChangeText | function | - | Text change callback |
| label | string | - | Label text |
| labelRequired | boolean | false | Show required asterisk |
| placeholder | string | - | Placeholder text |
| error | string | - | Error message |
| helperText | string | - | Helper text |
| leftIcon | ReactNode | - | Left icon |
| rightIcon | ReactNode | - | Right icon |
| secureTextEntry | boolean | false | Hide text |
| keyboardType | KeyboardType | 'default' | Keyboard type |
| multiline | boolean | false | Multiple lines |
| All standard TextInput props | - | - | Supports all React Native TextInput props |
OTPInput Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| otpLength | number | 6 | Number of OTP boxes (1-20) |
| otpValue | string | '' | Pre-filled OTP value |
| onOtpChange | (otp: string) => void | - | OTP change callback |
| otpAutoFocus | boolean | true | Auto focus first input |
| secureTextEntry | boolean | false | Hide OTP characters |
| Plus all base input props | - | - | Label, error, styling props |
SplitInput Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| splitFields | SplitField[] | [] | Field configurations |
| splitValues | SplitFieldValues | {} | Field values object |
| onSplitChange | function | - | Change callback |
| splitSpacing | number | 12 | Space between fields |
| Plus all base input props | - | - | Label, error, styling props |
SplitField Interface
interface SplitField {
key: string; // Unique identifier
label?: string; // Individual field label
labelRequired?: boolean; // Required indicator for field
placeholder?: string; // Field placeholder
flex?: number; // Width ratio (default: 1)
keyboardType?: KeyboardType; // Field keyboard type
autoCapitalize?: string; // Field capitalization
maxLength?: number; // Character limit
secureTextEntry?: boolean; // Hide text
editable?: boolean; // Enable/disable
}🎯 Advanced Features
OTP Features
- Smart Paste Support: Automatically distributes pasted content
- Fixed Backspace Navigation: Properly moves backward through fields
- Auto Focus Management: Seamless navigation between inputs
- Text Cleaning: Handles spaces and special characters in paste
- Customizable Length: Support for 1-20 character OTP
Split Fields Features
- Individual Field Labels: Each field can have its own label and required indicator
- Flexible Layout: Custom flex ratios for different field widths
- Mixed Input Types: Different keyboard types, validation per field
- Global + Individual Labels: Support for both overall and per-field labels
Performance Features
- Tree Shaking: Import only components you use
- Optimized Bundle Size: Up to 70% smaller with selective imports
- Shared Utilities: Common styles and utilities are reused
- TypeScript Optimized: Full type safety with minimal overhead
🔧 Migration Guide
Old Way (Still Supported)
import CustomTextInput from 'react-native-textinput-kit';
<CustomTextInput type="otp" otpLength={6} />New Way (Recommended)
import { OTPInput } from 'react-native-textinput-kit';
<OTPInput otpLength={6} />Split Fields Label Changes
Old Way
<CustomTextInput
type="split"
label="Full Name" // Single label for all fields
splitFields={[
{ key: 'first', placeholder: 'First Name' },
{ key: 'last', placeholder: 'Last Name' }
]}
/>New Way
<SplitInput
splitFields={[
{
key: 'first',
label: 'First Name', // Individual field label
labelRequired: true, // Individual required indicator
placeholder: 'Enter first name'
},
{
key: 'last',
label: 'Last Name',
placeholder: 'Enter last name'
}
]}
/>🎨 Theming Examples
Dark Theme
import { TextInput } from 'react-native-textinput-kit';
const darkTheme = {
labelStyle: { color: '#FFFFFF', fontWeight: '600' },
inputContainerStyle: {
backgroundColor: '#1F2937',
borderColor: '#374151',
},
inputStyle: { color: '#FFFFFF' },
focusedInputContainerStyle: {
borderColor: '#10B981',
},
errorStyle: { color: '#F87171' },
helperTextStyle: { color: '#9CA3AF' },
};
<TextInput
label="Dark Input"
placeholder="Enter text..."
{...darkTheme}
/>Custom OTP Theme
import { OTPInput } from 'react-native-textinput-kit';
<OTPInput
label="Verification Code"
otpLength={6}
onOtpChange={handleOtp}
// Rounded, colorful OTP boxes
otpInputContainerStyle={{
borderRadius: 12,
backgroundColor: '#EEF2FF',
borderColor: '#C7D2FE',
width: 50,
height: 60,
}}
otpFocusedInputContainerStyle={{
backgroundColor: '#4338CA',
borderColor: '#3730A3',
}}
otpInputStyle={{
fontSize: 20,
fontWeight: '700',
color: '#1E1B4B',
}}
otpFocusedInputStyle={{
color: '#FFFFFF',
}}
/>🧪 Form Validation Example
import React, { useState } from 'react';
import { View, Button, Alert } from 'react-native';
import { TextInput, OTPInput, SplitInput } from 'react-native-textinput-kit';
const FormExample = () => {
const [formData, setFormData] = useState({
email: '',
password: '',
otp: '',
name: {},
});
const [errors, setErrors] = useState({});
const validateEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const validateForm = () => {
const newErrors = {};
if (!formData.email || !validateEmail(formData.email)) {
newErrors.email = 'Please enter a valid email';
}
if (!formData.password || formData.password.length < 8) {
newErrors.password = 'Password must be at least 8 characters';
}
if (formData.otp.length !== 6) {
newErrors.otp = 'OTP must be 6 digits';
}
if (!formData.name.firstName) {
newErrors.name = 'First name is required';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = () => {
if (validateForm()) {
Alert.alert('Success', 'Form submitted successfully!');
}
};
return (
<View style={{ padding: 20 }}>
<TextInput
label="Email Address"
value={formData.email}
onChangeText={(email) => {
setFormData(prev => ({ ...prev, email }));
if (errors.email) setErrors(prev => ({ ...prev, email: '' }));
}}
keyboardType="email-address"
error={errors.email}
labelRequired
/>
<TextInput
label="Password"
value={formData.password}
onChangeText={(password) => {
setFormData(prev => ({ ...prev, password }));
if (errors.password) setErrors(prev => ({ ...prev, password: '' }));
}}
secureTextEntry
error={errors.password}
labelRequired
/>
<OTPInput
label="Verification Code"
onOtpChange={(otp) => {
setFormData(prev => ({ ...prev, otp }));
if (errors.otp) setErrors(prev => ({ ...prev, otp: '' }));
}}
error={errors.otp}
labelRequired
/>
<SplitInput
splitFields={[
{
key: 'firstName',
label: 'First Name',
labelRequired: true,
placeholder: 'First Name',
autoCapitalize: 'words'
},
{
key: 'lastName',
label: 'Last Name',
placeholder: 'Last Name',
autoCapitalize: 'words'
}
]}
splitValues={formData.name}
onSplitChange={(name) => {
setFormData(prev => ({ ...prev, name }));
if (errors.name) setErrors(prev => ({ ...prev, name: '' }));
}}
error={errors.name}
/>
<Button title="Submit Form" onPress={handleSubmit} />
</View>
);
};🔧 Ref Support
Access underlying TextInput methods:
import React, { useRef } from 'react';
import { TextInput } from 'react-native-textinput-kit';
const App = () => {
const inputRef = useRef<TextInput>(null);
const focusInput = () => {
inputRef.current?.focus();
};
return (
<TextInput
ref={inputRef}
label="Email"
placeholder="Enter email"
/>
);
};📱 Platform Support
- ✅ iOS - Full support with platform optimizations
- ✅ Android - Full support with platform optimizations
- ✅ Expo - Compatible with Expo managed workflow
- ✅ React Native CLI - Works with standard React Native projects
📋 Requirements
- React Native >= 0.60.0
- React >= 16.8.0
- TypeScript >= 4.0.0 (for TypeScript projects)
🎯 Roadmap
- [ ] Form Builder - Declarative form creation utilities
- [ ] Validation Hooks - Built-in validation patterns
- [ ] Accessibility - Enhanced screen reader support
- [ ] Animation Support - Smooth transitions and micro-interactions
- [ ] More Input Types - Slider, picker, date inputs
- [ ] Theming System - Comprehensive theme provider
📄 License
MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with React Native and TypeScript
- Optimized for modern bundlers with tree-shaking support
- Inspired by the need for flexible, performant form components
- Thanks to the React Native community for feedback and contributions
📞 Support
Made with ❤️ for the React Native community
