
Country code and dial code picker offers a customizable dropdown with flag support, search functionality, localization, and efficient performance, allowing easy retrieval of country details.
A Kotlin Multiplatform Country Code and Dial Code Picker with flag support and search functionality. This library provides a customizable dropdown component that enables users to:
| Platform | Supported |
|---|---|
| Android | ✔️ |
| iOS | ✔️ |
| Desktop | ✔️ |
| Web | ❌️ |
See the releases section of this repository for the latest version.
To your build.gradle under commonMain.dependencies add:
implementation "com.wannaverse:countryselector:<version>"Important this library uses native code to handle translations. You will need the additional dependencies depending on the targets you are building for:
Android under androidMain.dependencies:
implementation("com.wannaverse:countryselector-android:")
iOS (ARM) under iosMain.dependencies:
implementation("com.wannaverse:countryselector-iosarm64:")
iOS x64 under iosMain.dependencies:
implementation("com.wannaverse:countryselector-iosx64:")
jvm: implementation("com.wannaverse:countryselector-jvm:")
Below is a sample code that you may use.
Be aware: The Box is required if you are using any sort of scroll behavior with your screen. This is because this CountryPickerIcon uses a LazyColumn for it's scrollable functionality.
var selectedCountry by remember { mutableStateOf(Countries.US) }
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier.height(50.dp)
.border(
width = 1.dp,
color = MaterialTheme.colorScheme.outline,
shape = MaterialTheme.shapes.medium
)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
CountrySelector(
country = selectedCountry,
onSelection = { selectedCountry = it }
)
}
}To change the language of the country picker manually, before creating the CountryPickerIcon set:
Countries.languageTag = "es" // as long as it's a IETF language tagCountry names are translated automatically by the device OS. The picker's UI strings (search bar label, placeholder, empty state message) use Compose Multiplatform string resources and can be translated by contributing a locale file.
To add a translation, create a new file at:
countryselector/src/commonMain/composeResources/values-<language-code>/strings.xml
For example, for French (fr):
countryselector/src/commonMain/composeResources/values-fr/strings.xml
The file must define all 5 keys:
<resources>
<string name="no_countries_found"><!-- empty state message --></string>
<string name="search_label"><!-- search field label --></string>
<string name="search_placeholder"><!-- search field placeholder --></string>
<string name="search_content_description"><!-- search icon accessibility label --></string>
<string name="open_picker_content_description"><!-- dropdown arrow accessibility label --></string>
</resources>The correct string will be picked up automatically based on the device locale — no code changes needed. Use standard IETF language tags for the folder suffix (e.g. values-de, values-fr, values-zh, values-hi).
You can further customize the look and feel of the picker so that it's exactly how you want it:
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier
.height(50.dp)
.border(
width = 1.dp,
color = MaterialTheme.colorScheme.outline,
shape = MaterialTheme.shapes.medium
)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
CountrySelector(
country = selectedCountry,
onSelection = { selectedCountry = it },
pickerRowContent = { country ->
Row(
modifier = Modifier,
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(
resource = country.flagImageResource,
),
contentDescription = country.countryName,
modifier = Modifier
.size(24.dp)
.clip(CircleShape)
)
Spacer(Modifier.width(8.dp))
Text(country.countryName)
Spacer(Modifier.weight(1f))
Text(country.internationalDialCode)
} },
searchBarContent = { searchQuery, onQueryChange, hasError ->
TextField(
value = searchQuery,
onValueChange = onQueryChange,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
label = { Text("Search Countries") },
trailingIcon = {
if (hasError) {
Icon(Icons.Default.Error, contentDescription = "No results found")
} },
isError = hasError,
placeholder = { Text("Search by country name or code") }
)
}
)
}
}| Light Theme | Dark Theme |
|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| Light Theme | Dark Theme |
|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
MIT LICENSE. See LICENSE for details.
Pull requests and feature requests are welcome! If you encounter any issues, feel free to open an issue.
A Kotlin Multiplatform Country Code and Dial Code Picker with flag support and search functionality. This library provides a customizable dropdown component that enables users to:
| Platform | Supported |
|---|---|
| Android | ✔️ |
| iOS | ✔️ |
| Desktop | ✔️ |
| Web | ❌️ |
See the releases section of this repository for the latest version.
To your build.gradle under commonMain.dependencies add:
implementation "com.wannaverse:countryselector:<version>"Important this library uses native code to handle translations. You will need the additional dependencies depending on the targets you are building for:
Android under androidMain.dependencies:
implementation("com.wannaverse:countryselector-android:")
iOS (ARM) under iosMain.dependencies:
implementation("com.wannaverse:countryselector-iosarm64:")
iOS x64 under iosMain.dependencies:
implementation("com.wannaverse:countryselector-iosx64:")
jvm: implementation("com.wannaverse:countryselector-jvm:")
Below is a sample code that you may use.
Be aware: The Box is required if you are using any sort of scroll behavior with your screen. This is because this CountryPickerIcon uses a LazyColumn for it's scrollable functionality.
var selectedCountry by remember { mutableStateOf(Countries.US) }
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier.height(50.dp)
.border(
width = 1.dp,
color = MaterialTheme.colorScheme.outline,
shape = MaterialTheme.shapes.medium
)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
CountrySelector(
country = selectedCountry,
onSelection = { selectedCountry = it }
)
}
}To change the language of the country picker manually, before creating the CountryPickerIcon set:
Countries.languageTag = "es" // as long as it's a IETF language tagCountry names are translated automatically by the device OS. The picker's UI strings (search bar label, placeholder, empty state message) use Compose Multiplatform string resources and can be translated by contributing a locale file.
To add a translation, create a new file at:
countryselector/src/commonMain/composeResources/values-<language-code>/strings.xml
For example, for French (fr):
countryselector/src/commonMain/composeResources/values-fr/strings.xml
The file must define all 5 keys:
<resources>
<string name="no_countries_found"><!-- empty state message --></string>
<string name="search_label"><!-- search field label --></string>
<string name="search_placeholder"><!-- search field placeholder --></string>
<string name="search_content_description"><!-- search icon accessibility label --></string>
<string name="open_picker_content_description"><!-- dropdown arrow accessibility label --></string>
</resources>The correct string will be picked up automatically based on the device locale — no code changes needed. Use standard IETF language tags for the folder suffix (e.g. values-de, values-fr, values-zh, values-hi).
You can further customize the look and feel of the picker so that it's exactly how you want it:
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier
.height(50.dp)
.border(
width = 1.dp,
color = MaterialTheme.colorScheme.outline,
shape = MaterialTheme.shapes.medium
)
.padding(8.dp),
contentAlignment = Alignment.Center
) {
CountrySelector(
country = selectedCountry,
onSelection = { selectedCountry = it },
pickerRowContent = { country ->
Row(
modifier = Modifier,
verticalAlignment = Alignment.CenterVertically
) {
Image(
painter = painterResource(
resource = country.flagImageResource,
),
contentDescription = country.countryName,
modifier = Modifier
.size(24.dp)
.clip(CircleShape)
)
Spacer(Modifier.width(8.dp))
Text(country.countryName)
Spacer(Modifier.weight(1f))
Text(country.internationalDialCode)
} },
searchBarContent = { searchQuery, onQueryChange, hasError ->
TextField(
value = searchQuery,
onValueChange = onQueryChange,
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
label = { Text("Search Countries") },
trailingIcon = {
if (hasError) {
Icon(Icons.Default.Error, contentDescription = "No results found")
} },
isError = hasError,
placeholder = { Text("Search by country name or code") }
)
}
)
}
}| Light Theme | Dark Theme |
|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| Light Theme | Dark Theme |
|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
MIT LICENSE. See LICENSE for details.
Pull requests and feature requests are welcome! If you encounter any issues, feel free to open an issue.