phone_text_field 2.0.0

SDKflutter
Platformandroidioswindowslinuxmacosweb

Phone Number TextFiled is a Flutter plugin that allows you to parse, validate, format and other utilities for to international phone numbers and allow localization.

📱 Phone Text Field

Pub Version Flutter Platform License GitHub Stars

A comprehensive Flutter package for international phone number input with validation, formatting, and country selection. Perfect for apps requiring phone number collection with proper validation and beautiful UI.

🚀 Live Demo

🌐 Try the Interactive Web Demo - Experience all features in your browser!

📱 Mobile Demo: Clone and run the example app to see it in action on mobile devices.

✨ Demo

Phone Text Field Demo

🎯 Key Features

🌍 International Support

  • 200+ countries with proper validation rules
  • Automatic formatting based on country standards
  • Real-time validation with visual feedback
  • Smart country detection from phone numbers

🎨 Customizable UI

  • Material 3 Design support
  • Dark/Light theme compatibility
  • Flexible styling options
  • Custom decorations for input fields
  • Responsive design for web and mobile

🔧 Developer-Friendly

  • TextEditingController support for form integration
  • Validation callbacks with custom error messages
  • Localization support (Arabic, English, French)
  • TypeScript-like strongly typed API
  • Well-documented with comprehensive examples

🐛 Recent Bug Fixes (v1.0.0+)

  • Fixed controller integration - Proper TextEditingController support
  • Fixed +1 country codes - US/Canada flag switching issue resolved
  • Fixed Chinese validation - Corrected 11-digit validation for China
  • Improved performance - Optimized country selection logic

📦 Installation

1. Add Dependency

Add this to your pubspec.yaml:

dependencies:
  phone_text_field: ^1.0.0 # Use latest version

2. Install

flutter pub get

3. Import

import 'package:phone_text_field/phone_text_field.dart';

🔥 Quick Start

Basic Usage

PhoneTextField(
  onChanged: (phoneNumber) {
    print('Complete number: ${phoneNumber.completeNumber}');
    print('Country: ${phoneNumber.countryISOCode}');
  },
)

With Controller (Form Integration)

class MyForm extends StatefulWidget {
  @override
  _MyFormState createState() => _MyFormState();
}

class _MyFormState extends State<MyForm> {
  final _phoneController = TextEditingController();
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: PhoneTextField(
        controller: _phoneController,
        isRequired: true,
        autovalidateMode: AutovalidateMode.onUserInteraction,
        decoration: const InputDecoration(
          labelText: 'Phone Number',
          border: OutlineInputBorder(),
        ),
        onChanged: (phoneNumber) {
          // Handle phone number changes
        },
      ),
    );
  }

  @override
  void dispose() {
    _phoneController.dispose();
    super.dispose();
  }
}

🎨 Advanced Examples

Custom Styling with Material 3

PhoneTextField(
  initialCountryCode: 'AE',
  decoration: const InputDecoration(
    filled: true,
    labelText: 'Phone Number',
    border: OutlineInputBorder(
      borderRadius: BorderRadius.all(Radius.circular(12)),
    ),
    prefixIcon: Icon(Icons.phone),
  ),
  searchFieldInputDecoration: const InputDecoration(
    filled: true,
    border: OutlineInputBorder(
      borderRadius: BorderRadius.all(Radius.circular(12)),
    ),
    suffixIcon: Icon(Icons.search),
    hintText: 'Search country',
  ),
  countryViewOptions: CountryViewOptions.countryCodeWithFlag,
  onChanged: (phoneNumber) {
    debugPrint('Phone: ${phoneNumber.completeNumber}');
  },
)

Arabic Localization

PhoneTextField(
  locale: const Locale('ar'),
  decoration: const InputDecoration(
    filled: true,
    labelText: 'رقم الهاتف',
    border: OutlineInputBorder(
      borderRadius: BorderRadius.all(Radius.circular(12)),
    ),
    prefixIcon: Icon(Icons.phone),
  ),
  searchFieldInputDecoration: const InputDecoration(
    filled: true,
    border: OutlineInputBorder(
      borderRadius: BorderRadius.all(Radius.circular(12)),
    ),
    suffixIcon: Icon(Icons.search),
    hintText: 'بحث عن بالاسم او الرمز',
  ),
  dialogTitle: 'اختر الدولة',
  initialCountryCode: 'AE',
  onChanged: (phoneNumber) {
    debugPrint('رقم الهاتف: ${phoneNumber.completeNumber}');
  },
)

Validation & Error Handling

PhoneTextField(
  isRequired: true,
  invalidNumberMessage: 'Please enter a valid phone number',
  autovalidateMode: AutovalidateMode.onUserInteraction,
  decoration: const InputDecoration(
    labelText: 'Phone Number *',
    border: OutlineInputBorder(),
    helperText: 'Enter your phone number with country code',
  ),
  onChanged: (phoneNumber) {
    if (phoneNumber.isValid) {
      print('Valid number: ${phoneNumber.completeNumber}');
    }
  },
)

Different Country Display Options

// Flag only
PhoneTextField(
  countryViewOptions: CountryViewOptions.countryFlagOnly,
  onChanged: (phoneNumber) {},
)

// Country name with flag
PhoneTextField(
  countryViewOptions: CountryViewOptions.countryNameWithFlag,
  onChanged: (phoneNumber) {},
)

// Country code only
PhoneTextField(
  countryViewOptions: CountryViewOptions.countryCodeOnly,
  onChanged: (phoneNumber) {},
)

📋 API Reference

PhoneTextField Properties

PropertyTypeDefaultDescription
onChangedFunction(PhoneNumber)requiredCallback when phone number changes
controllerTextEditingController?nullController for form integration
initialCountryCodeString?nullInitial country code (e.g., 'US', 'AE')
initialValueString?nullInitial phone number value
decorationInputDecoration?nullInput field decoration
searchFieldInputDecorationInputDecoration?nullCountry search field decoration
localeLocale?nullLocalization (ar, en, fr)
isRequiredboolfalseWhether the field is required
invalidNumberMessageString?nullCustom validation error message
countryViewOptionsCountryViewOptionscountryCodeWithFlagHow to display countries
dialogTitleString?nullCustom dialog title
autovalidateModeAutovalidateMode?nullWhen to validate input

PhoneNumber Object

class PhoneNumber {
  String completeNumber;      // Full international number
  String countryISOCode;      // Country code (US, AE, etc.)
  String countryCode;         // Dial code (+1, +971, etc.)
  String number;              // Local number
  bool isValid;               // Validation status
}

CountryViewOptions

enum CountryViewOptions {
  countryCodeOnly,           // +1
  countryNameOnly,           // United States
  countryFlagOnly,           // 🇺🇸
  countryCodeWithFlag,       // 🇺🇸 +1
  countryNameWithFlag,       // 🇺🇸 United States
}

🔧 Integration Examples

With Form Validation

class PhoneForm extends StatefulWidget {
  @override
  _PhoneFormState createState() => _PhoneFormState();
}

class _PhoneFormState extends State<PhoneForm> {
  final _formKey = GlobalKey<FormState>();
  final _phoneController = TextEditingController();
  PhoneNumber? _phoneNumber;

  @override
  Widget build(BuildContext context) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          PhoneTextField(
            controller: _phoneController,
            isRequired: true,
            autovalidateMode: AutovalidateMode.onUserInteraction,
            decoration: const InputDecoration(
              labelText: 'Phone Number *',
              border: OutlineInputBorder(),
            ),
            onChanged: (phoneNumber) {
              setState(() {
                _phoneNumber = phoneNumber;
              });
            },
          ),
          const SizedBox(height: 20),
          ElevatedButton(
            onPressed: () {
              if (_formKey.currentState!.validate() &&
                  _phoneNumber?.isValid == true) {
                // Process valid phone number
                print('Valid phone: ${_phoneNumber!.completeNumber}');
              }
            },
            child: const Text('Submit'),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    _phoneController.dispose();
    super.dispose();
  }
}

With Bloc/Provider State Management

// Using Provider
class PhoneProvider extends ChangeNotifier {
  PhoneNumber? _phoneNumber;

  PhoneNumber? get phoneNumber => _phoneNumber;

  void updatePhone(PhoneNumber phoneNumber) {
    _phoneNumber = phoneNumber;
    notifyListeners();
  }
}

// In your widget
Consumer<PhoneProvider>(
  builder: (context, phoneProvider, child) {
    return PhoneTextField(
      onChanged: (phoneNumber) {
        phoneProvider.updatePhone(phoneNumber);
      },
    );
  },
)

🐛 Bug Fixes & Improvements

Version 1.0.0+ Fixes

✅ Controller Integration Issue (#2)

Problem: Controller property was commented out, causing integration issues with forms.

// Before (broken)
// final TextEditingController? controller;

// After (fixed)
final TextEditingController? controller;

✅ +1 Country Code Flag Switching (#3)

Problem: When editing US/Canada numbers, flag would incorrectly switch between countries. Solution: Improved country selection logic to preserve originally selected country when multiple countries share the same dial code.

✅ Chinese Phone Number Validation (#4)

Problem: Chinese numbers were validated as 12 digits instead of 11.

// Before
'CN': {minLength: 12, maxLength: 12}

// After
'CN': {minLength: 11, maxLength: 11}

Testing the Fixes

You can test these fixes in the example app or the live demo:

  1. Controller Test: Use the form integration examples
  2. +1 Countries Test: Try switching between US (+1) and Canada (+1)
  3. Chinese Numbers Test: Enter a Chinese number like 13812345678

🌍 Supported Countries

This package supports 200+ countries with proper validation rules including:

  • 🇺🇸 United States (+1)
  • 🇨🇦 Canada (+1)
  • 🇬🇧 United Kingdom (+44)
  • 🇦🇪 United Arab Emirates (+971)
  • 🇨🇳 China (+86)
  • 🇮🇳 India (+91)
  • 🇧🇷 Brazil (+55)
  • 🇩🇪 Germany (+49)
  • 🇫🇷 France (+33)
  • 🇯🇵 Japan (+81)
  • And many more...

🌐 Localization

The package supports multiple languages:

LanguageLocaleStatus
Englishen✅ Full Support
Arabicar✅ Full Support
Frenchfr✅ Full Support

Adding New Languages

Contributions for additional languages are welcome! Check our contribution guide for details.

📱 Platform Support

PlatformStatusNotes
📱 iOS✅ Full SupportiOS 9.0+
🤖 Android✅ Full SupportAPI 16+
🌐 Web✅ Full SupportAll modern browsers
🖥️ macOS✅ Full SupportmacOS 10.11+
🖥️ Windows✅ Full SupportWindows 10+
🐧 Linux✅ Full SupportAny distribution

🎯 Examples & Demos

📱 Example App

Run the comprehensive example app:

cd example
flutter run

🌐 Web Demo

Experience the full demo in your browser:

cd example
flutter run -d chrome

📋 Code Examples

📸 Screenshots

Country Selection
🌍 Country Selection
Easy country selection with search functionality
Phone Input
📱 Phone Input
Clean phone number input with validation
Arabic Localization
🇸🇦 Arabic Localization
Full RTL support with Arabic text
Validation
✅ Validation & Error Handling
Real-time validation with error messages

🎬 Live Demo

Phone Text Field Demo

Interactive demo showing all features in action


🎨 Key Features Grid

International Support

🌍 International
200+ countries with proper validation rules
Customizable Design

🎨 Customizable
Material 3 design with flexible styling
Localization Support

🌐 Localized
Arabic, English, French support
Validation System

✅ Validation
Real-time validation with custom messages

� Feature Showcase

✨ Feature📷 Preview📝 Description
🌍 InternationalCountry flags200+ countries with proper validation rules
🎨 CustomizableStyled inputMaterial 3 design with flexible styling
🌐 LocalizedArabic UIArabic, English, French support
ValidationError statesReal-time validation with custom messages

🤝 Contributing

We welcome contributions! Here's how you can help:

🐛 Report Bugs

  • Use the issue tracker
  • Include reproduction steps and Flutter/Dart versions
  • Check existing issues first

✨ Request Features

  • Open a feature request
  • Describe the use case and expected behavior
  • Consider contributing the implementation

🔧 Submit Pull Requests

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes and add tests
  4. Ensure all tests pass: flutter test
  5. Commit with conventional commits: git commit -m "feat: add amazing feature"
  6. Push to your fork: git push origin feature/amazing-feature
  7. Open a Pull Request

📝 Development Setup

# Clone the repository
git clone https://github.com/MohamedAbd0/phone_text_field.git
cd phone_text_field

# Install dependencies
flutter pub get

# Run tests
flutter test

# Run example app
cd example
flutter run

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

👨‍💻 Author

Mohamed Abdo

⭐ Show Your Support

If this package helped you, please:

  • Star the repository on GitHub
  • 👍 Like the package on pub.dev
  • 🐦 Share it on social media
  • 💝 Consider sponsoring the project

📊 Stats

GitHub stars Pub points Pub popularity GitHub issues GitHub pull requests


Made with ❤️ by Mohamed Abdo

⬆ Back to Top