Flutter Flag Selector
A customizable country picker for Flutter: SVG flags, dial codes, country names in 20 languages and four display modes. Built for phone number inputs, sign-up flows and international forms.
Demo
| Bottom sheet | Dialog | Popup menu | Draggable sheet |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Search ranks the best match first | Same picker, centered | Anchored to the selector | Drag the list to resize the sheet |

Country names follow flagSelectorLanguageCode: English, French, Japanese and 17 more.
Features
| Feature | Details |
|---|---|
| Countries | 213 countries and territories, with ISO 2 and ISO 3 codes, dial codes, currencies and time zones |
| Flags | SVG flags, sharp at any size |
| Languages | Country names in 20 languages |
| Display modes | Bottom sheet, dialog, popup menu, draggable sheet |
| Search | By country name, ISO code or dial code; exact codes and names starting with the query come first |
| Smart default | Preselects the device's country when no initial country is set |
| Keyboard aware | The bottom sheets stay above the keyboard while searching |
| Customization | 30+ properties, plus builders for the flag, the items and the whole picker |
| Platforms | Android, iOS, Web, macOS, Windows, Linux |
Installation
Add flutter_flag_selector to your pubspec.yaml file:
dependencies:
flutter_flag_selector: ^1.0.2
Then run:
flutter pub get
Quick Start
Basic Country Picker
The simplest way to use the country picker:
import 'package:flutter/material.dart';
import 'package:flutter_flag_selector/flutter_flag_selector.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FlagSelector(
onFlagSelectorCountryChanged: (country) {
print('Selected country: ${country.name}');
print('Country code: ${country.code}');
print('Dial code: ${country.dialCode}');
},
),
),
);
}
}
Without flagSelectorInitialCountry, the selector preselects the device's country (read from the platform locale), then falls back to the first country of the list. Set flagSelectorUseDeviceCountry: false to disable this.
Examples
Example 1: Phone Number Input with Country Code
Perfect for international phone number inputs:
FlagSelector(
flagSelectorLanguageCode: 'en',
flagSelectorInitialCountry: 'us',
flagSelectorOptionType: FlagSelectorOptionType.modalBottomSheet,
onFlagSelectorCountryChanged: (country) {
// Update phone number input with country dial code
phoneNumberController.text = country.dialCode;
},
flagSelectorTextStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
)
Example 2: Customized Bottom Sheet
Create a beautifully customized bottom sheet flag selector:
FlagSelector(
flagSelectorOptionType: FlagSelectorOptionType.modalBottomSheet,
flagSelectorModalTitle: 'Choose Your Country',
flagSelectorModalTitleStyle: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.blue,
),
flagSelectorSelectedCountryItemColor: Colors.blue.shade100,
flagSelectorCountryItemHeight: 60.0,
onFlagSelectorCountryChanged: (country) {
print('Selected: ${country.name}');
},
)
Example 3: Dialog Mode
Use a centered dialog for country selection:
FlagSelector(
flagSelectorOptionType: FlagSelectorOptionType.dialog,
flagSelectorModalTitle: 'Select Country',
flagSelectorModalHeightFactor: 0.8,
onFlagSelectorCountryChanged: (country) {
Navigator.pop(context);
// Handle country selection
},
)
Example 4: Popup Menu Mode
Compact popup menu for space-constrained layouts:
FlagSelector(
flagSelectorOptionType: FlagSelectorOptionType.popupMenu,
flagSelectorWidth: 200,
flagSelectorHeight: 50,
onFlagSelectorCountryChanged: (country) {
print('Country: ${country.name}');
},
)
Example 5: Multi-Language Support
Display country names in different languages:
FlagSelector(
flagSelectorLanguageCode: 'fr', // French
onFlagSelectorCountryChanged: (country) {
print(country.getName('fr')); // Get French name
},
)
// Or switch dynamically
String currentLanguage = 'es'; // Spanish
FlagSelector(
flagSelectorLanguageCode: currentLanguage,
onFlagSelectorCountryChanged: (country) {
print(country.getName(currentLanguage));
},
)
Example 6: Form Integration
Integrate with Flutter forms:
class CountryForm extends StatefulWidget {
@override
_CountryFormState createState() => _CountryFormState();
}
class _CountryFormState extends State<CountryForm> {
Country? selectedCountry;
@override
Widget build(BuildContext context) {
return Form(
child: Column(
children: [
FlagSelector(
flagSelectorInitialCountry: selectedCountry?.code,
onFlagSelectorCountryChanged: (country) {
setState(() {
selectedCountry = country;
});
},
),
if (selectedCountry != null)
Text('Selected: ${selectedCountry!.name} (${selectedCountry!.dialCode})'),
],
),
);
}
}
Example 7: Custom Styling
Fully customize the appearance:
FlagSelector(
flagSelectorDecoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.blue, width: 2),
boxShadow: [
BoxShadow(
color: Colors.blue.withOpacity(0.1),
blurRadius: 10,
spreadRadius: 2,
),
],
),
flagSelectorTextStyle: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.blue.shade900,
),
flagSelectorFlagWidth: 40,
flagSelectorFlagHeight: 30,
flagSelectorGap: 12,
onFlagSelectorCountryChanged: (country) {
// Handle selection
},
)
Example 8: Filtered Country List
Show only specific countries:
FlagSelector(
flagSelectorCountries: [
CountryService.byCode('us')!,
CountryService.byCode('ca')!,
CountryService.byCode('gb')!,
CountryService.byCode('fr')!,
CountryService.byCode('de')!,
],
onFlagSelectorCountryChanged: (country) {
print('Selected: ${country.name}');
},
)
Example 9: Advanced Search Configuration
Customize the search functionality:
FlagSelector(
flagSelectorShowSearch: true,
flagSelectorSearchHintText: 'Search by name or code...',
flagSelectorSearchDecoration: InputDecoration(
prefixIcon: Icon(Icons.search),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
),
onFlagSelectorCountryChanged: (country) {
// Handle selection
},
)
Example 10: Draggable Sheet Mode
Use the draggable sheet for a modern UX:
FlagSelector(
flagSelectorOptionType: FlagSelectorOptionType.draggableSheet,
flagSelectorModalTitle: 'Choose Country',
onFlagSelectorCountryChanged: (country) {
print('Selected: ${country.name}');
},
)
Use Cases
1. Phone Number Input Forms
Perfect for apps requiring international phone number input. The country picker automatically provides the correct dial code for each country.
2. User Registration
Allow users to select their country during registration. The flag selector provides an intuitive interface with visual country flags.
3. Shipping Address Forms
E-commerce apps can use the country picker in shipping address forms to help users quickly select their destination country.
4. Language Selection
Use the multi-language support to display country names in the user's preferred language, improving the international user experience.
5. Analytics and Reporting
Track user locations by country selection, useful for analytics and understanding your user base distribution.
6. Currency Selection
Since each country includes currency information, you can use the country picker to help users select their preferred currency.
7. Timezone Selection
Countries include timezone data, making it easy to implement timezone selection based on country choice.
🎌 Supported Languages
The Flutter Flag Selector package supports the following languages for country name translations:
| Code | Language | Example |
|---|---|---|
| en | English | Andorra |
| ru | Russian | Андорра |
| pl | Polish | Andora |
| ua | Ukrainian | Андорра |
| cz | Czech | Andorra |
| by | Belarusian | Андора |
| pt | Portuguese | Andorra |
| es | Spanish | Andorra |
| ro | Romanian | Andorra |
| bg | Bulgarian | Андора |
| de | German | Andorra |
| fr | French | Andorre |
| nl | Dutch | Andorra |
| it | Italian | Andorra |
| cn | Chinese | 安道尔 |
| ee | Estonian | Andorra |
| jp | Japanese | アンドラ |
| he | Hebrew | אנדורה |
| tr | Turkish | Andorra |
| ar | Arabic | أندورا |
You can set the display language using the flagSelectorLanguageCode property:
FlagSelector(
flagSelectorLanguageCode: 'fr', // Display country names in French
// other properties...
)
🎯 Display Modes
The package supports 4 different display modes for selecting countries:
- Modal Bottom Sheet (default) - A bottom sheet that slides up from the bottom
- Dialog - A centered dialog modal
- Popup Menu - A popup menu positioned relative to the selector
- Draggable Sheet - A resizable sheet that can be dragged up and down
You can choose the display mode using the flagSelectorOptionType property:
FlagSelector(
flagSelectorOptionType: FlagSelectorOptionType.dialog, // or modalBottomSheet, popupMenu, draggableSheet
// other properties...
)
API Reference
Main Selector Properties
| Property | Type | Description | Default Value |
|---|---|---|---|
flagSelectorLanguageCode |
String | Language code for country names | 'en' |
flagSelectorOptionType |
FlagSelectorOptionType | Display mode (modalBottomSheet, dialog, popupMenu, draggableSheet) | modalBottomSheet |
flagSelectorCountries |
List | Available countries list | defaultCountries |
flagSelectorInitialCountry |
String? | Initially selected country code (ISO 2 letters) | null |
flagSelectorUseDeviceCountry |
bool | Preselect the device's country when no initial country is given | true |
onFlagSelectorCountryChanged |
ValueChanged | Function called when a country is selected | null |
flagSelectorPadding |
EdgeInsetsGeometry? | Internal padding of the selector | null |
flagSelectorDecoration |
BoxDecoration? | Decoration of the main container | Default decoration with border radius |
flagSelectorBackgroundColor |
Color? | Background color of the selector | null |
flagSelectorGap |
double | Space between elements | 8.0 |
flagSelectorWidth |
double? | Selector width | null (automatic) |
flagSelectorHeight |
double? | Selector height | null (automatic) |
flagSelectorClipBehavior |
Clip? | How to clip the selector's content | Clip.none |
flagSelectorConstraints |
BoxConstraints? | Size constraints for the selector | null |
flagSelectorForegroundDecoration |
Decoration? | Foreground decoration drawn on top of the selector | null |
flagSelectorTransform |
Matrix4? | Transform to apply to the selector | null |
flagSelectorTransformAlignment |
AlignmentGeometry? | Alignment of the transform operation | null |
flagSelectorMargin |
EdgeInsetsGeometry? | External margin of the selector | null |
flagSelectorFlagWidth |
double | Flag width | 30.0 |
flagSelectorFlagHeight |
double | Flag height | 20.0 |
flagSelectorFlagBuilder |
Widget Function(BuildContext, Country)? | Custom builder for the flag | null |
flagSelectorTextStyle |
TextStyle? | Text style for the country name | Theme.of(context).textTheme.bodyMedium |
flagSelectorCountryNameBuilder |
String Function(Country)? | Custom builder for the country name | null |
flagSelectorDropdownIcon |
Widget? | Custom dropdown icon | Icon(Icons.arrow_drop_down) |
flagSelectorIconSize |
double | Icon size | 24.0 |
flagSelectorIconColor |
Color? | Icon color | Theme.of(context).iconTheme.color |
Modal Properties
| Property | Type | Description | Default Value |
|---|---|---|---|
flagSelectorModalBuilder |
ModalPickerBuilder? | Custom builder for the entire modal | null |
flagSelectorPickerStyle |
CountryPickerStyle? | Global style for the picker | Default style |
flagSelectorShowModalTitle |
bool | Show the modal title | true |
flagSelectorModalTitle |
String? | Modal title text | 'Select Country' |
flagSelectorModalTitleStyle |
TextStyle? | Modal title style | Theme.of(context).textTheme.titleMedium |
flagSelectorModalTitlePadding |
EdgeInsetsGeometry? | Padding for the modal title | null |
flagSelectorModalHeightFactor |
double | Modal height (as a factor of the screen) | 0.7 |
flagSelectorCountryItemBuilder |
CountryItemBuilder? | Custom builder for country items | null |
flagSelectorCountryItemPadding |
EdgeInsetsGeometry? | Padding for country items | null |
flagSelectorCountryItemHeight |
double? | Height of country items | null |
flagSelectorCountryItemColor |
Color? | Background color of country items | null |
flagSelectorSelectedCountryItemColor |
Color? | Background color for the selected country | Colors.blueAccent |
Search Properties
| Property | Type | Description | Default Value |
|---|---|---|---|
flagSelectorSearchBuilder |
SearchInputBuilder? | Custom builder for the search input | null |
flagSelectorSearchDecoration |
InputDecoration? | Decoration for the search input | null |
flagSelectorSearchTextStyle |
TextStyle? | Style for search text | null |
flagSearchEnabled |
bool? | Enable/disable search | true |
flagSelectorSearchHintText |
String? | Hint text for search | 'Search countries...' |
flagSelectorSearchPadding |
EdgeInsetsGeometry? | Padding for the search input | null |
flagSelectorShowSearch |
bool | Show the search bar | true |
flagSelectorSearchContainerColor |
Color? | Background color of the search container | null |
flagSelectorSearchContainerBorderRadius |
BorderRadius? | Border radius of the search container | null |
flagSelectorSearchContainerBorder |
BoxBorder? | Border of the search container | null |
flagSelectorSearchContainerShadow |
List | Shadows of the search container | null |
flagSelectorSearchContainerMargin |
EdgeInsetsGeometry? | Margins of the search container | null |
flagSelectorSearchContainerPadding |
EdgeInsetsGeometry? | Padding of the search container | null |
flagSelectorSearchInputPadding |
EdgeInsetsGeometry? | Padding of the search input | null |
flagSelectorSearchContainerWidth |
double? | Width of the search container | null |
flagSelectorSearchContainerHeight |
double? | Height of the search container | null |
flagSelectorSearchContainerConstraints |
BoxConstraints? | Constraints of the search container | null |
Country Model
The package uses a comprehensive Country model with the following properties:
class Country {
final String code; // ISO 2-letter code (e.g., 'us')
final String name; // Country name (in English)
final String dialCode; // Phone dial code (e.g., '+1')
final String iso3; // ISO 3-letter code (e.g., 'USA')
final String currency; // Currency code (e.g., 'USD')
final String currencyName; // Currency name (e.g., 'US Dollar')
final String emoji; // Flag emoji (e.g., '🇺🇸')
final List<String> timezones; // Timezones (e.g., ['UTC-05:00'])
final String region; // Region (e.g., 'Americas')
final Map<String, String> translations; // Name translations in multiple languages
}
Using the Country Service
The package also includes a service for working with country data:
// Initialize the service (do this at app startup)
CountryService.initialize();
// Get a country by code
Country? usa = CountryService.byCode('us');
// Search countries by currency
List<Country> euroCountries = CountryService.byCurrency('EUR');
// Search countries by region
List<Country> europeanCountries = CountryService.byRegion('Europe');
// Advanced search
List<Country> results = CountryService.advancedSearch(
region: 'Europe',
currency: 'EUR',
query: 'fr'
);
Flag Assets
The package includes SVG flags for all countries. These assets are bundled with the package and accessed automatically. If you want to use custom flag images, you can provide your own implementation using the flagSelectorFlagBuilder property.
Troubleshooting
Issue: Flags not displaying
Solution: Ensure that flutter_svg is properly added to your dependencies. The flags are SVG files bundled with the package.
Issue: Country names not in the correct language
Solution: Verify that you're using a supported language code. Check the Supported Languages section for available codes.
Issue: Modal not closing after selection
Solution: This should happen automatically. If it doesn't, ensure you're using the latest version of the package. You can also manually close the modal in the onFlagSelectorCountryChanged callback.
Issue: Search not working
Solution: Make sure flagSelectorShowSearch is set to true (default) and flagSearchEnabled is not set to false.
Issue: Initial country not selected
Solution: Verify that the flagSelectorInitialCountry value is a valid ISO 2-letter country code (e.g., 'us', 'fr', 'jp'). The code is case-insensitive.
Issue: Custom styling not applying
Solution: Ensure you're using the correct property names. All customization properties start with flagSelector. Check the API Reference for the complete list of properties.
Issue: Performance issues with large country lists
Solution: The package is optimized for performance, but if you're using a very large custom country list, consider filtering the list to only include relevant countries.
Contributing
Contributions are welcome! We love to see the community getting involved. Here's how you can help:
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Make your changes following our code style guidelines
- Add tests for new features
- Update documentation (README.md, CHANGELOG.md)
- Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Setup
- Clone the repository
- Run
flutter pub get - Run
flutter analyzeto check for issues - Run
flutter testto run tests - Check the example app in the
example/folder
Code Style
- Follow the Dart Style Guide
- Use meaningful variable and function names
- Add documentation comments for public APIs
- Write tests for new features
License
This project is licensed under the MIT License - see the LICENSE file for details.
Links
Made with ❤️ for the Flutter community



