ReactTutorialCountries
How to Build a Country Selector in React with ApogeoAPI
ApogeoAPI6 min read
Country selectors are one of the most common UI components — shipping forms, user profiles, tax settings. Here's how to build a production-ready one with flags and search using ApogeoAPI.
What We're Building
A searchable dropdown that:
- Shows a flag emoji + country name for each option
- Filters as the user types
- Returns the selected country's ISO code
- Uses TypeScript throughout
Step 1: Get Your Free API Key
Sign up at app.apogeoapi.com — the free tier includes countries + states forever. No credit card needed.
Step 2: Fetch the Countries
// types.ts
export interface Country {
iso2: string;
name: string;
flag_url: string;
region: string;
}
// useCountries.ts
import { useEffect, useState } from 'react';
export function useCountries() {
const [countries, setCountries] = useState<Country[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.apogeoapi.com/v1/countries', {
headers: { 'X-API-Key': process.env.NEXT_PUBLIC_APOGEO_API_KEY! }
})
.then(r => r.json())
.then(data => setCountries(data))
.finally(() => setLoading(false));
}, []);
return { countries, loading };
}
Step 3: Build the Selector Component
// CountrySelector.tsx
'use client';
import { useState } from 'react';
import { useCountries } from './useCountries';
interface Props {
value: string;
onChange: (isoCode: string) => void;
}
export function CountrySelector({ value, onChange }: Props) {
const { countries, loading } = useCountries();
const [search, setSearch] = useState('');
const filtered = countries.filter(c =>
c.name.toLowerCase().includes(search.toLowerCase())
);
if (loading) return <div>Loading countries...</div>;
return (
<div className="relative">
<input
type="text"
placeholder="Search countries..."
value={search}
onChange={e => setSearch(e.target.value)}
className="w-full border rounded px-3 py-2"
/>
<ul className="absolute z-10 w-full bg-white border rounded max-h-60 overflow-y-auto">
{filtered.map(country => (
<li
key={country.iso2}
onClick={() => onChange(country.iso2)}
className={`flex items-center gap-2 px-3 py-2 cursor-pointer hover:bg-gray-100 ${
value === country.iso2 ? 'bg-blue-50' : ''
}`}
>
<img src={country.flag_url} alt="" className="w-5 h-4 object-cover rounded-sm" />
<span>{country.name}</span>
</li>
))}
</ul>
</div>
);
}
Step 4: Use It in Your Form
import { CountrySelector } from './CountrySelector';
function ShippingForm() {
const [country, setCountry] = useState('');
return (
<form>
<label>Country</label>
<CountrySelector value={country} onChange={setCountry} />
</form>
);
}
Enhancements
- Cache the response — countries don't change often. Use SWR or React Query with a long staleTime.
- Add states/provinces — once a country is selected, fetch
GET /v1/countries/{iso2}/statesfor a cascading state selector. - Phone codes — ApogeoAPI returns
phone_codeper country — useful for phone number inputs.
What's Next
With the same API key, you can add city autocomplete (GET /v1/countries/{iso2}/cities), detect the user's country from IP (GET /v1/geolocate/{ip}), and display live prices in their local currency — all in one subscription.
Try ApogeoAPI free
1,000 requests/month forever. 14-day full-access trial. No credit card.
Get your free API key