Реализация выбора региона/страны пользователем на сайте
Выбор страны или региона — элемент, который встречается в регистрационных формах, настройках профиля, фильтрах каталога и лендингах с локализованным контентом. Реализация зависит от количества вариантов и сценария использования.
Варианты реализации
<select> с полным списком стран — самый простой способ. Достаточно для форм, где геовыбор не критичен. Недостаток: 200 стран в обычном дропдауне неудобно листать.
Searchable dropdown — поле ввода + фильтруемый список. Библиотеки: react-select, downshift, headlessui Combobox. Оптимально для большинства случаев.
Флаги + код страны — для телефонных форм, где пользователь выбирает код (+7, +380). Библиотека react-phone-number-input решает эту задачу в комплексе.
Карта — для выбора региона внутри страны. Реализуется через SVG-карту или Leaflet/Mapbox с кликабельными полигонами.
Searchable dropdown на примере React
import { Combobox } from '@headlessui/react';
import { useState } from 'react';
import { countries } from './countries-data'; // ISO 3166-1 список
function CountrySelector({ value, onChange }) {
const [query, setQuery] = useState('');
const filtered = query.length < 1
? countries
: countries.filter(c =>
c.name.toLowerCase().includes(query.toLowerCase()) ||
c.code.toLowerCase().includes(query.toLowerCase())
);
return (
<Combobox value={value} onChange={onChange}>
<Combobox.Input
onChange={e => setQuery(e.target.value)}
displayValue={c => c?.name ?? ''}
placeholder="Выберите страну"
className="country-input"
/>
<Combobox.Options className="country-dropdown">
{filtered.length === 0 && query.length > 0 ? (
<div className="country-empty">Страна не найдена</div>
) : (
filtered.map(country => (
<Combobox.Option key={country.code} value={country}>
{({ active }) => (
<div className={`country-option ${active ? 'active' : ''}`}>
<img
src={`/flags/${country.code.toLowerCase()}.svg`}
width={20}
alt=""
aria-hidden
/>
{country.name}
<span className="country-code">{country.code}</span>
</div>
)}
</Combobox.Option>
))
)}
</Combobox.Options>
</Combobox>
);
}
Данные: откуда брать список стран
-
Статический JSON — файл с ISO 3166-1 (код, название на нужных языках, dial-код). Пакет
world-countries(~180 KB) или собственный облегчённый список -
REST Countries API —
https://restcountries.com/v3.1/all— актуальные данные, но внешняя зависимость -
База на сервере — таблица
countriesс переводами, фильтрация по активным регионам поставки
Автоопределение по IP
Предустанавливать страну по геолокации — улучшает UX, но требует бэкенда:
// Laravel + Torann/GeoIP или MaxMind
public function detectCountry(Request $request): JsonResponse
{
$geo = geoip()->getLocation($request->ip());
return response()->json([
'country_code' => $geo->iso_code,
'country_name' => $geo->country,
]);
}
На фронте:
useEffect(() => {
fetch('/api/geo/country')
.then(r => r.json())
.then(geo => {
const detected = countries.find(c => c.code === geo.country_code);
if (detected && !value) onChange(detected); // только если не выбрано вручную
});
}, []);
Сроки
Searchable dropdown с флагами, поиском и автоопределением по IP — 1–2 рабочих дня.







