flutter_country_phone 0.1.1 copy "flutter_country_phone: ^0.1.1" to clipboard
flutter_country_phone: ^0.1.1 copied to clipboard

Country catalog, localized country picker, SVG flags, and international phone form fields for Flutter apps.

flutter_country_phone #

Country catalog, localized country picker, SVG flags, and international phone form fields for Flutter apps.

flutter_country_phone gives you a reusable foundation for forms that need a country selector, a phone input with country prefix handling, or a simple way to render country names and flags. It ships with its own static country catalog and flag assets, so your app does not need to duplicate those resources.

Features #

  • Static country catalog with ISO 3166-1 alpha-2 codes, phone prefixes, and localized country names.
  • Package-owned SVG flags through CountryFlag.
  • CountryBloc to load and reuse the country catalog across fields.
  • CountryFormField for selecting a country inside a Form.
  • PhoneFormField for collecting an international phone number.
  • CountryField and PhoneField lower-level widgets when you do not need a FormField wrapper.
  • Search by localized country name, ISO code, or phone prefix.
  • onlyCountries filtering for restricted country lists.
  • CountryPhoneFieldStyle plus item/button builders for UI customization.
  • Locale fallback support for values such as es, es_MX, es-MX, pt_BR, and pt-BR.

Installation #

Add the package to your pubspec.yaml:

dependencies:
  flutter_country_phone: ^0.1.1

The package declares its own flag assets. No extra asset registration is needed in your app.

Basic setup #

Provide a CountryBloc once near the part of the app that uses country or phone fields:

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_country_phone/flutter_country_phone.dart';

BlocProvider(
  create: (_) => CountryBloc()..fetchCountries(),
  child: const MyApp(),
)

You can also register CountryBloc in your app-level MultiBlocProvider if the country catalog is used in multiple features.

Country picker #

Use CountryFormField when the selected country is part of a Form:

CountryFormField(
  value: 'US',
  decoration: const InputDecoration(
    labelText: 'Country',
    hintText: 'Select your country',
  ),
  validator: (country) {
    if (country == null) return 'Select a country';
    return null;
  },
  onChanged: (country) {
    debugPrint(country?.iso2); // US
  },
)

Restrict the list when a flow supports only a few countries:

CountryFormField(
  onlyCountries: const ['US', 'BR', 'ES'],
  showPhoneCode: true,
  onChanged: (country) {
    debugPrint('${country?.iso2} ${country?.phoneCode}');
  },
)

If you need a plain widget instead of a form field, use CountryField:

CountryField(
  decoration: const InputDecoration(labelText: 'Country'),
  locale: 'pt-BR',
  onChanged: (country) {
    debugPrint(country.iso2);
  },
)

International phone field #

PhoneFormField lets the user select a country first and then enter the national phone number. The onChanged value is the international number string generated by phone_numbers_parser.

PhoneFormField(
  decoration: const InputDecoration(
    labelText: 'Phone number',
    hintText: 'Enter your phone number',
  ),
  textInputAction: TextInputAction.next,
  autofillHints: const [AutofillHints.telephoneNumber],
  validator: (value) {
    if (value == null || value.isEmpty) return 'Enter a phone number';
    return null;
  },
  onChanged: (value) {
    debugPrint(value); // Example: +15551234567
  },
)

You can pass an existing international number as the initial value:

PhoneFormField(
  initialValue: '+5511999999999',
  decoration: const InputDecoration(labelText: 'Phone'),
)

When the initial value is parseable and its country is allowed, the field opens directly in phone-entry mode with the matching country selected.

Rendering countries and flags #

Use CountryFlag when you only need a flag:

const CountryFlag(
  isoCode: 'BR',
  size: 24,
  borderRadius: BorderRadius.all(Radius.circular(4)),
)

Use CountryWidget when you need the localized country name with the flag:

const CountryWidget(
  iso: 'ES',
  flagSize: 18,
)

CountryWidget also reads from CountryBloc, so make sure the bloc is available in the widget tree.

Localization #

Widgets use Localizations.localeOf(context) by default. You can override the locale when a field needs to render in a specific language:

CountryFormField(
  locale: 'es-MX',
  decoration: const InputDecoration(labelText: 'País'),
)

Locale values can be language-only (es) or region-specific (es_MX, es-MX, pt_BR, pt-BR). The lookup tries the full locale, then the language code, then English, then the first non-empty available value.

You can also customize labels with a builder:

CountryFormField(
  countryLabelBuilder: (context, country) {
    return country.localizedName('pt-BR');
  },
)

For app-specific empty states, pass emptyBuilder.

Styling #

Most visual customization is intentionally grouped into CountryPhoneFieldStyle:

const countryPhoneStyle = CountryPhoneFieldStyle(
  overlayMaxHeight: 260,
  overlayBorderRadius: BorderRadius.all(Radius.circular(18)),
  overlayElevation: 10,
  overlayPadding: EdgeInsets.all(8),
  itemPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 14),
  itemBorderRadius: BorderRadius.all(Radius.circular(14)),
  flagSize: 24,
  selectedFlagSize: 20,
  flagFit: BoxFit.cover,
);

CountryFormField(
  style: countryPhoneStyle,
)

For deeper customization, replace the country item or selected-country button:

PhoneFormField(
  countryItemBuilder: (context, country, selected) {
    return ListTile(
      leading: CountryFlag(isoCode: country.iso2, size: 22),
      title: Text(country.localizedName('es')),
      trailing: Text(country.phoneCode),
      selected: selected,
    );
  },
  selectedCountryButtonBuilder: (context, country, onPressed) {
    return TextButton.icon(
      onPressed: onPressed,
      icon: CountryFlag(isoCode: country.iso2),
      label: Text(country.phoneCode),
    );
  },
)

Working with the catalog #

You can use the catalog directly through the datasource/use case stack:

final bloc = CountryBloc();

await bloc.fetchCountries();

final countries = bloc.countries;
final unitedStates = countries.firstWhere((country) => country.iso2 == 'US');

CountryBloc keeps the loaded countries in memory. Calling fetchCountries() again will reuse the current list unless force: true is passed internally by refreshCountries().

API notes #

  • CountryEntity is immutable, extends Equatable, and includes copyWith.
  • CountryModel extends CountryEntity and provides fromJson, fromEntity, and toJson.
  • CountryModel.fromJson accepts phoneCode or phone_code and normalizes ISO codes to uppercase.
  • Phone formatting and parsing are delegated to phone_numbers_parser.
  • The package is UI-framework friendly: use the widgets directly or keep the domain/data classes for app-specific wrappers.

Development #

Run the local checks before publishing:

flutter analyze
flutter test
flutter pub publish --dry-run

License #

MIT License. See LICENSE.

2
likes
140
points
229
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Country catalog, localized country picker, SVG flags, and international phone form fields for Flutter apps.

Repository (GitHub)
View/report issues

Topics

#country-picker #phone-field #flags #form #localization

License

MIT (license)

Dependencies

collection, equatable, flutter, flutter_bloc, flutter_svg, phone_numbers_parser

More

Packages that depend on flutter_country_phone