npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

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-kit

or

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 total

Legacy 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