npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-paper-country-picker

v1.2.7

Published

A customizable React Native Paper country picker with searchable modal, flags, and dialing codes.

Readme

react-native-paper-country-picker

npm version license CI

A customizable React Native Paper country picker with:

  • 🌍 195 countries with flags (via react-native-country-flag)
  • 🔍 Searchable modal — search by name (EN or ES), ISO code, dial code, or currency code
  • 📞 Dial code + phone input — flag + code selector with an editable phone number field
  • 💱 Currency support — ISO 4217 codes + symbols for all countries
  • 🌐 Bilingual — English and Spanish names, UI strings in both languages
  • 🇬🇹 Default country — pre-select any country on mount (defaults to Guatemala)
  • Preferred countries pinned to the top of the list
  • 🚫 Excluded countries support
  • 🎛 displayMode — configure what the input shows after selection
  • 🖊 inputMode'outlined' (border) or 'flat' (underline) for all display modes
  • 🎨 Fully customizable — style overrides, custom row renderer, custom input renderer
  • ♿ Full accessibility labels
  • 💙 Built on top of react-native-paper — matches your app's Material theme out of the box

Preview


Installation

npm install react-native-paper-country-picker react-native-country-flag
# or
yarn add react-native-paper-country-picker react-native-country-flag

Peer dependencies

Make sure you have these installed in your project:

npm install react-native-paper

react-native-paper requires wrapping your app in a <PaperProvider>. See the react-native-paper docs.


Usage

Basic — Country selector

import { useState } from 'react';
import { CountryPickerInput, type Country } from 'react-native-paper-country-picker';

export default function MyForm() {
  const [country, setCountry] = useState<Country | null>(null);

  return (
    <CountryPickerInput
      label="Country"
      value={country}
      onSelect={setCountry}
      helperText="Select your country of residence"
    />
  );
}

Default country (Guatemala pre-selected)

Use defaultCountry to pre-select a country when the component mounts and no value is provided. Defaults to 'GT' (Guatemala).

<CountryPickerInput
  value={country}
  onSelect={setCountry}
  defaultCountry="GT"  // ISO code — any country from the list
/>

displayMode="dialCode" — Phone input with editable number

Shows the flag + dial code selector on the left and an editable phone number TextInput on the right. Guatemala is pre-selected by default.

const [country, setCountry] = useState<Country | null>(null);
const [phone, setPhone] = useState('');

<CountryPickerInput
  displayMode="dialCode"
  defaultCountry="GT"
  value={country}
  onSelect={setCountry}
  phoneNumber={phone}
  onChangePhoneNumber={setPhone}
  preferredCountries={['GT', 'MX', 'SV', 'US']}
  language="es"
/>

// Full number: country.dialCode + ' ' + phone  →  "+502 5555 5555"

Phone input props

| Prop | Type | Description | |------|------|-------------| | phoneNumber | string | Controlled value for the phone number field | | onChangePhoneNumber | (phone: string) => void | Callback when the number changes | | phonePlaceholder | string | Placeholder text for the phone number field | | phoneInputProps | TextInputProps (partial) | Extra props forwarded to the phone TextInput (e.g. maxLength, keyboardType) |


displayMode="currency" — Currency selector

Show the flag, currency symbol and ISO 4217 code.

const [currency, setCurrency] = useState<Country | null>(null);

<CountryPickerInput
  displayMode="currency"
  value={currency}
  onSelect={setCurrency}
/>

// After selecting Guatemala    → shows: 🇬🇹 Q GTQ
// After selecting United States → shows: 🇺🇸 $ USD
// After selecting Germany      → shows: 🇩🇪 € EUR

inputMode — flat or outlined

Controls the visual style of the input field. Works for all displayMode values (name, dialCode, currency).

// Outlined (default) — border all around
<CountryPickerInput
  inputMode="outlined"
  value={country}
  onSelect={setCountry}
/>

// Flat — underline only, no border radius
<CountryPickerInput
  inputMode="flat"
  displayMode="dialCode"
  value={country}
  onSelect={setCountry}
  phoneNumber={phone}
  onChangePhoneNumber={setPhone}
/>

| Value | Appearance | |-------|-----------| | 'outlined' (default) | Full border + borderRadius: 4, selector background #F5F5F5 | | 'flat' | Bottom border only, no radius, white background throughout |


Spanish language

<CountryPickerInput
  language="es"
  displayMode="dialCode"
  value={country}
  onSelect={setCountry}
  preferredCountries={['GT', 'MX', 'SV']}
/>
// Label → "Prefijo telefónico"
// Placeholder → "Selecciona prefijo"
// Country names → in Spanish

Preferred and excluded countries

<CountryPickerInput
  value={country}
  onSelect={setCountry}
  preferredCountries={['GT', 'MX', 'SV', 'US']}
  excludedCountries={['KP', 'CU']}
/>

Custom styles

Use the styles prop to override individual sections of the component:

import { type CountryPickerStyles } from 'react-native-paper-country-picker';

const darkStyles: CountryPickerStyles = {
  phoneInputContainer: {
    borderColor: '#30363D',
    borderRadius: 8,
    backgroundColor: '#161B22',
  },
  dialCodeSelector: {
    backgroundColor: '#0D1117',
    borderRightColor: '#30363D',
  },
  dialCodeText: { color: '#58A6FF', fontWeight: '700' },
  phoneInput: { color: '#E6EDF3' },
  modal: { backgroundColor: '#161B22', borderWidth: 1, borderColor: '#30363D' },
  modalTitle: { color: '#E6EDF3' },
};

<CountryPickerInput
  displayMode="dialCode"
  defaultCountry="GT"
  value={country}
  onSelect={setCountry}
  styles={darkStyles}
/>

CountryPickerStyles reference

| Key | Type | Targets | |-----|------|---------| | container | ViewStyle | Outer wrapper of the whole component | | modal | ViewStyle | The picker modal container | | modalTitle | TextStyle | Modal title text | | searchInput | ViewStyle | Search TextInput inside the modal | | countryRow | ViewStyle | Each country row in the modal list | | phoneInputContainer | ViewStyle | Outer row for flag+code+number (dialCode mode) | | dialCodeSelector | ViewStyle | The pressable flag+code button | | dialCodeText | TextStyle | The +502 code label | | phoneInput | TextStyle | The editable phone number field |


Custom row renderer

Replace the default country row in the modal list:

<CountryPickerInput
  displayMode="dialCode"
  value={country}
  onSelect={setCountry}
  renderCountryRow={(country, onSelect) => (
    <Pressable onPress={() => onSelect(country)} style={myRowStyle}>
      <CountryFlag isoCode={country.isoCode} size={24} />
      <Text>{country.nameEs}</Text>
      <Text>{country.dialCode}</Text>
    </Pressable>
  )}
/>

Custom input renderer

Replace the entire trigger input (the tappable field that opens the modal):

<CountryPickerInput
  value={country}
  onSelect={setCountry}
  renderInput={(country, onOpen) => (
    <Pressable onPress={onOpen} style={myInputStyle}>
      {country && <CountryFlag isoCode={country.isoCode} size={20} />}
      <Text>{country?.name ?? 'Select country'}</Text>
    </Pressable>
  )}
/>

selectProps — Customize the dial code selector pressable

Forward extra props to the Pressable that wraps the flag + dial code in dialCode mode. Useful for hitSlop, testID, accessibilityLabel, etc.

<CountryPickerInput
  displayMode="dialCode"
  value={country}
  onSelect={setCountry}
  selectProps={{
    hitSlop: { top: 14, bottom: 14, left: 14, right: 14 },
    accessibilityLabel: 'Open country selector',
    testID: 'dial-code-selector',
  }}
/>

Note: onPress and style are managed internally. Use styles.dialCodeSelector to customize the appearance.


Accessing the selected country

The onSelect callback receives the full Country object:

const handleSelect = (country: Country) => {
  console.log(country);
  // {
  //   name: "Guatemala",
  //   nameEs: "Guatemala",
  //   isoCode: "GT",
  //   dialCode: "+502",
  //   currency: "GTQ",
  //   currencySymbol: "Q"
  // }
};

API

<CountryPickerInput />

| Prop | Type | Default | Description | |------|------|---------|-------------| | value | Country \| null | — | Currently selected country | | onSelect | (country: Country) => void | — | Called when a country is selected | | displayMode | CountryDisplayMode | 'name' | Controls what is shown in the input after selection | | defaultCountry | string | 'GT' | ISO code of the country to pre-select on mount when no value is set | | inputMode | 'flat' \| 'outlined' | 'outlined' | Visual style — full border or underline only | | label | string | auto | Label for the text input | | placeholder | string | auto | Placeholder when no country is selected | | searchPlaceholder | string | auto | Placeholder for the modal search input | | modalTitle | string | auto | Title at the top of the picker modal | | language | 'en' \| 'es' | 'en' | Language for UI strings and country names | | showDialCode | boolean | false | Show the dial code alongside the name in the modal list | | preferredCountries | string[] | [] | ISO codes of countries pinned to the top of the list | | excludedCountries | string[] | [] | ISO codes of countries to hide from the list | | searchable | boolean | true | Show or hide the search input in the modal | | disabled | boolean | false | Disables the picker | | error | boolean | false | Puts the input in an error state | | helperText | string | — | Helper text displayed below the input | | phoneNumber | string | — | Controlled value for the phone number field (dialCode mode) | | onChangePhoneNumber | (phone: string) => void | — | Callback when phone number changes (dialCode mode) | | phonePlaceholder | string | auto | Placeholder for the phone number field | | phoneInputProps | TextInputProps (partial) | — | Extra props for the phone TextInput | | styles | CountryPickerStyles | — | Style overrides per section | | selectProps | PressableProps (partial) | — | Extra props for the dial code selector Pressable | | renderCountryRow | (country, onSelect) => ReactNode | — | Custom renderer for each modal row | | renderInput | (country, onOpen) => ReactNode | — | Custom renderer for the input trigger |


CountryDisplayMode

Controls what is displayed inside the input after a country is selected.

type CountryDisplayMode = 'name' | 'dialCode' | 'currency';

| Value | Input shows | Auto label (EN) | Auto label (ES) | |-------|-------------|-----------------|--------------------| | 'name' | 🇬🇹 Guatemala | Country | País | | 'dialCode' | 🇬🇹 +502 [editable field] | Phone prefix | Prefijo telefónico | | 'currency' | 🇬🇹 Q GTQ | Currency | Moneda |


Country type

interface Country {
  /** Country name in English (e.g. "Mexico") */
  name: string;
  /** Country name in Spanish (e.g. "México") */
  nameEs: string;
  /** ISO 3166-1 alpha-2 code (e.g. "MX") */
  isoCode: string;
  /** International dial code (e.g. "+52") */
  dialCode: string;
  /** ISO 4217 currency code (e.g. "MXN") */
  currency: string;
  /** Currency symbol (e.g. "$") */
  currencySymbol: string;
}

COUNTRIES

You can import the full countries array for custom filtering or advanced use cases:

import { COUNTRIES } from 'react-native-paper-country-picker';

// Filter to Latin American countries
const latam = COUNTRIES.filter(c =>
  ['MX', 'GT', 'SV', 'HN', 'NI', 'CR', 'PA', 'CO', 'VE', 'PE', 'BO', 'CL', 'AR', 'UY', 'PY', 'EC', 'BR'].includes(c.isoCode)
);

// Get all Euro countries
const euroZone = COUNTRIES.filter(c => c.currency === 'EUR');

// Get all countries with USD
const usdCountries = COUNTRIES.filter(c => c.currency === 'USD');

Changelog

v1.2.5

  • 🚀 Complete refactor of standard select input (StandardSelectInput): uses pure React Native flexbox layout matching Material 3 specifications. Completely replaces Paper TextInput.Icon custom component rendering, eliminating Fabric Android text layout measurement crashes (Layout: -1 < 0) once and for all while providing 100% pure white background across all modes.

v1.2.4

  • 🐛 Completely remove pointerEvents prop from wrapper Pressable (fixes Fabric Android layout measurement error Layout: -1 < 0)

v1.2.3

  • 🐛 Explicitly set width: '100%' on Pressable wrapper to fix Fabric Android text layout measurement (Layout: -1 < 0)

v1.2.2

  • 🐛 Fix Android Fabric (New Architecture) crash java.lang.IllegalArgumentException: Layout: -1 < 0 by removing inner pointerEvents="none" wrapper View and using pointerEvents="box-only" on Pressable

v1.2.1

  • 🏳️ Default all inputs (including flat mode for name and currency modes) to white background (#FFFFFF) instead of MD3 purple surfaceVariant
  • 🎨 Add styles.textInput support to CountryPickerStyles to easily override main input styles
  • 🛡️ Add defensive fallback for invalid displayMode values (defaults to 'name' instead of throwing error)

v1.2.0

  • 🇬🇹 New defaultCountry prop — pre-select any country on mount (defaults to 'GT')
  • 📞 displayMode="dialCode" now renders an editable phone number field alongside the flag+code selector
  • 🖊 New inputMode prop ('flat' | 'outlined') — works for all display modes including dialCode
  • 🎨 New styles prop (CountryPickerStyles) — fine-grained style overrides per section
  • 🧩 New renderCountryRow prop — custom renderer for each country row in the modal
  • 🧩 New renderInput prop — custom renderer for the input trigger
  • 🎛 New selectProps prop — extra Pressable props for the dial code selector (hitSlop, testID, etc.)
  • ⬇️ Larger chevron icon for improved visibility
  • 🏳️ White background on phone input container in all modes
  • 📦 CountryPickerStyles type exported from library entry point

v1.1.0

  • ✨ New displayMode prop: 'name' | 'dialCode' | 'currency'
  • 💱 Added currency (ISO 4217) and currencySymbol fields to all 195 countries
  • 🔍 Search now also works on currency codes
  • 🏷 Auto label/placeholder defaults per displayMode and language
  • 📋 Modal row subtitle adapts to the active displayMode
  • 📦 Export CountryDisplayMode type from library entry point

v1.0.0

  • 🎉 Initial release
  • 🌍 195 countries with flags
  • 🌐 Bilingual support (EN + ES)
  • 📞 Dial code support
  • ⭐ Preferred and excluded countries
  • 🔍 Searchable modal

Contributing

See CONTRIBUTING.md.

License

MIT — see LICENSE.


Made with ❤️ using create-react-native-library