phone_input_plus 0.2.0 copy "phone_input_plus: ^0.2.0" to clipboard
phone_input_plus: ^0.2.0 copied to clipboard

A customizable phone input field with auto country detection, formatting and validation. Perfect for African and international phone numbers.

πŸ“± phone_input_plus #

A customizable Flutter phone input field with automatic country detection, smart formatting, and validation. Perfect for African and international phone numbers.

pub package pub points popularity likes License: MIT

✨ Features #

  • Auto Country Detection - Detects user's country via IP or device locale
  • Intelligent Paste Detection - Auto-detects country from pasted international numbers
  • Smart Formatting - Real-time number formatting as you type
  • Dynamic Length Limitation - Automatically limits input based on country
  • Adaptive Keyboard - Automatically chooses the best keyboard type
  • Built-in Validation - Country-specific phone number validation
  • Highly Customizable - Extensive styling and configuration options
  • 52 African Countries - Comprehensive support for African phone numbers
  • International Support - Works worldwide with any country
  • Multiple Selector Types - BottomSheet, Dialog, or Full Page
  • Search Functionality - Quick country search with multi-language support
  • Smart Caching - Caches detected country for better performance
  • Controller Support - Full programmatic control like TextField

πŸ“Έ Screenshots #

Basic Basic Example BottomSheet Country Controller Example Dialog Country Validation Example

πŸš€ Getting Started #

Installation #

Add this to your pubspec.yaml:

dependencies:
  phone_input_plus: ^0.0.1

Then run:

flutter pub get

Import #

import 'package:phone_input_plus/phone_input_plus.dart';

πŸ’‘ Basic Usage #

Simple Phone Input #

The most basic usage with auto country detection:

PhoneInputField(
  decoration: const InputDecoration(
    labelText: 'Phone Number',
    border: OutlineInputBorder(),
  ),
  onChanged: (PhoneNumber phone) {
    print('International: ${phone.international}');
    print('Valid: ${phone.isValid}');
  },
)

With Initial Country #

Set a specific initial country:

PhoneInputField(
  initialCountry: CountryData.benin,
  autoDetect: false, // Disable auto-detection
  decoration: const InputDecoration(
    labelText: 'Phone Number',
    border: OutlineInputBorder(),
  ),
)

Limited Country List #

Restrict to specific countries (e.g., West Africa only):

PhoneInputField(
  countries: const [
    CountryData.benin,
    CountryData.gabon,
    CountryData.senegal,
    CountryData.coteDivoire,
    CountryData.cameroon,
  ],
  decoration: const InputDecoration(
    labelText: 'Phone Number',
    border: OutlineInputBorder(),
  ),
)

🎯 Advanced Usage #

Using PhoneController #

For programmatic control, use PhoneController:

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late PhoneController _controller;

  @override
  void initState() {
    super.initState();
    _controller = PhoneController(
      initialCountry: CountryData.benin,
    );
    
    // Listen to changes
    _controller.addListener(() {
      print('Phone changed: ${_controller.international}');
    });
  }

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

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        PhoneInputField(
          controller: _controller,
          decoration: const InputDecoration(
            labelText: 'Phone Number',
            border: OutlineInputBorder(),
          ),
        ),
        
        // Programmatic actions
        ElevatedButton(
          onPressed: () => _controller.changeCountry(CountryData.france),
          child: const Text('Switch to France'),
        ),
        ElevatedButton(
          onPressed: () => _controller.clear(),
          child: const Text('Clear'),
        ),
      ],
    );
  }
}

Form Validation #

Integrate with Flutter forms:

Form(
  key: _formKey,
  child: PhoneInputField(
    decoration: const InputDecoration(
      labelText: 'Phone Number *',
      border: OutlineInputBorder(),
    ),
    validator: (phone) {
      if (phone == null || phone.isEmpty) {
        return 'Phone number is required';
      }
      if (!phone.isValid) {
        return 'Invalid phone number for ${phone.country.nameEn}';
      }
      return null;
    },
    onSubmitted: (phone) {
      if (_formKey.currentState!.validate()) {
        // Submit form
      }
    },
  ),
)

⌨️ Keyboard Type & Paste Detection #

Intelligent Paste Detection #

By default, PhoneInputField supports intelligent paste detection. When a user pastes an international number like +2290166640219, the widget automatically:

  1. Detects the country (Benin in this case)
  2. Changes the country selector
  3. Extracts the national number
  4. Formats it correctly
PhoneInputField(
  enablePasteDetection: true,  // Default
  decoration: const InputDecoration(
    labelText: 'Phone Number',
    hintText: 'Paste +2290166640219',
    border: OutlineInputBorder(),
  ),
)

Keyboard Behavior #

The keyboard type is automatically chosen based on paste detection:

Paste Detection Keyboard Type Behavior
Enabled (default) Text keyboard Allows pasting numbers with +
Disabled Numeric keyboard Better UX for manual entry

Disable paste detection for numeric keyboard:

PhoneInputField(
  enablePasteDetection: false,  // Numeric keyboard
  decoration: const InputDecoration(
    labelText: 'Phone Number',
    border: OutlineInputBorder(),
  ),
)

Manual Override #

You can manually specify the keyboard type:

PhoneInputField(
  keyboardType: TextInputType.phone,  // Force numeric keyboard
  enablePasteDetection: false,  // Disable paste (won't work with numeric)
)

Or try to keep both features with:

PhoneInputField(
  keyboardType: const TextInputType.numberWithOptions(signed: true),
  enablePasteDetection: true,  // May work on some devices
)

Note: The ability to paste numbers with + on numeric keyboards varies by device and OS.

🌍 Country Detection #

The package automatically detects the user's country using multiple strategies:

  1. IP-based detection (primary) - Uses free IP geolocation APIs
  2. Device locale (fallback) - Uses the device's locale settings
  3. Smart caching - Caches the detected country for 24 hours

Disable Auto-Detection #

PhoneInputField(
  autoDetect: false,
  initialCountry: CountryData.benin,
)

Custom Cache Duration #

PhoneInputField(
  detectionCacheDuration: 48, // Cache for 48 hours
)

βœ… Validation #

Built-in Validation #

Each country has specific validation rules:

final phone = PhoneNumber(
  country: CountryData.benin,
  nationalNumber: '0166640219',
);

print(phone.isValid); // true - valid Benin number
print(phone.formatted); // "01 66 64 02 19"
print(phone.international); // "+2290166640219"

Custom Validator #

Add your own validation logic:

PhoneInputField(
  validator: (phone) {
    if (phone == null || phone.isEmpty) {
      return 'Required';
    }
    
    // Custom rule: Only mobile numbers
    if (phone.country.code == 'FR' && 
        !phone.nationalNumber.startsWith('6') &&
        !phone.nationalNumber.startsWith('7')) {
      return 'Only mobile numbers allowed';
    }
    
    if (!phone.isValid) {
      return 'Invalid number';
    }
    
    return null;
  },
)

🎨 Customization #

Country Button Style #

Customize the country selector button:

PhoneInputField(
  countryButtonStyle: const CountryButtonStyle(
    showDialCode: false, // Hide dial code
    padding: EdgeInsets.all(8),
    flagStyle: TextStyle(fontSize: 32), // Bigger flag
  ),
)

Country Selector Type #

Choose between BottomSheet, Dialog, or Page:

PhoneInputField(
  countrySelectorConfig: const CountrySelectorConfig(
    type: CountrySelectorType.dialog, // or .bottomSheet, .page
    title: 'Choose Country',
    searchHint: 'Search...',
    locale: 'fr', // Show country names in French
  ),
)

Disable Auto-Formatting #

Show raw numbers without spaces:

PhoneInputField(
  autoFormat: false,
)

Custom Decoration #

Full control over the TextField appearance:

PhoneInputField(
  decoration: InputDecoration(
    labelText: 'Mobile',
    hintText: 'Enter your number',
    prefixIcon: const Icon(Icons.phone),
    border: OutlineInputBorder(
      borderRadius: BorderRadius.circular(12),
    ),
    filled: true,
    fillColor: Colors.grey[100],
  ),
)

πŸ“š Available Countries #

Quick Access #

// Individual countries (52 African countries)
CountryData.benin
CountryData.nigeria
CountryData.southAfrica
CountryData.kenya
CountryData.ghana
// ... and 47 more African countries

// Non-African
CountryData.france
CountryData.usa
CountryData.canada

Regions #

  • Africa: 52 countries (complete coverage)
  • Europe: France, Belgium, Switzerland, Germany, Italy, Spain, Portugal, Netherlands, UnitedKingdom, Ireland,
  • Americas: USA, Canada, Mexico, Brazil, Argentina, Chile, Colombia, Peru, Venezuela, DominicanRepublic

More countries will be added in future releases based on user feedback.

Search Countries #

// Search by name (English)
final results = CountryData.search('Benin');

// Search by name (French)
final results = CountryData.search('BΓ©nin', locale: 'fr');

// Get country by code
final benin = CountryData.getByCode('BJ');

// Get country by dial code
final benin = CountryData.getByDialCode('+229');

πŸ”§ API Reference #

PhoneInputField #

Parameter Type Default Description
controller PhoneController? null Optional controller for programmatic control
initialCountry Country? null Initial country (ignored if controller provided)
countries List<Country> All countries List of available countries
autoDetect bool true Auto-detect user's country
autoFormat bool true Format number as user types
enablePasteDetection bool true Enable intelligent paste detection
keyboardType TextInputType? null Keyboard type (auto-detected if null)
validator Function? null Custom validation function
onChanged Function? null Callback when number changes
onCountryChanged Function? null Callback when country changes
decoration InputDecoration? null TextField decoration
enabled bool true Enable/disable the field
readOnly bool false Make field read-only

PhoneController #

Method Description
changeCountry(Country) Change the selected country
updateNumber(String) Update the phone number
clear() Clear the number (keep country)
reset(Country) Reset with new country
Getter Type Description
country Country Current country
nationalNumber String National number (no dial code)
international String Full international number
formatted String Formatted number
isValid bool Is number valid?

PhoneNumber #

Property Type Description
country Country The country
nationalNumber String National number
international String International format
formatted String Formatted display
isValid bool Validation status

🀝 Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

Adding More Countries #

To add support for additional countries, edit lib/src/core/data/countries_*.dart files.

πŸ“„ License #

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

πŸ’¬ Support #

For issues, questions, or feature requests, please open an issue.


Made with ❀️ in Benin πŸ‡§πŸ‡―

1
likes
160
points
233
downloads

Publisher

unverified uploader

Weekly Downloads

A customizable phone input field with auto country detection, formatting and validation. Perfect for African and international phone numbers.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter, http, shared_preferences

More

Packages that depend on phone_input_plus