Skip to content

WannaverseOfficial/kmp-country-selector

Repository files navigation

Wannaverse Logo

Build iOS Build Linux

🚩 Country Selector

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:

  • Search and select any country
  • Retrieve the country name, ISO country code (GB, US, FR etc.)
  • Get the country dial code (+44, +1, +33 etc.)
  • Display the country flag and retrieve usable a flag resource
  • View countries in their native device language e.g. instead of "Germany", a German user will see "Deutschland"

🧩 Features

  • 🌍 Full list of countries and dial codes
  • 🔍 Search by name or dial code
  • 🎏 Native flag support
  • 📦 Lightweight & efficient
  • ♻️ Kotlin Multiplatform compatible
  • 🌐 Built-in localization support

✅ Supported Platform

Platform Supported
Android ✔️
iOS ✔️
Desktop ✔️
Web ❌️

🚀 Installation

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:")

Usage

KDocs

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 tag

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") }
                )
            }
        )
    }
}

Screenshots

Android

Light Theme Dark Theme

iOS

Light Theme Dark Theme

📄 License

MIT LICENSE. See LICENSE for details.

🙌 Contributing

Pull requests and feature requests are welcome! If you encounter any issues, feel free to open an issue.