@juniorov/cr-locations
v1.0.1
Published
Provincias, cantones y distritos de Costa Rica con funciones para poblar selects/dropdowns encadenados.
Downloads
77
Maintainers
Readme
@juniorov/cr-locations
Provincias, cantones y distritos de Costa Rica, listos para poblar dropdowns encadenados (provincia → cantón → distrito) en cualquier framework.
Instalación
npm install @juniorov/cr-locationsUso
import { getProvinces, getCantons, getDistricts } from "@juniorov/cr-locations";
// 1. Cargar el dropdown de provincias
const provinces = getProvinces();
// [{ id: "1", name: "San José" }, { id: "2", name: "Alajuela" }, ...]
// 2. Al elegir una provincia, cargar sus cantones
const cantons = getCantons("1");
// [{ id: "01", name: "Central" }, { id: "02", name: "Escazú" }, ...]
// 3. Al elegir un cantón, cargar sus distritos
const districts = getDistricts("1", "01");
// [{ id: "01", name: "Carmen" }, { id: "02", name: "Merced" }, ...]Ejemplo con JavaScript vanilla (3 <select> encadenados)
<select id="province"><option value="">Provincia</option></select>
<select id="canton" disabled><option value="">Cantón</option></select>
<select id="district" disabled><option value="">Distrito</option></select>
<script type="module">
import { getProvinces, getCantons, getDistricts } from "@juniorov/cr-locations";
const $province = document.getElementById("province");
const $canton = document.getElementById("canton");
const $district = document.getElementById("district");
function fillSelect($select, options, placeholder) {
$select.innerHTML = `<option value="">${placeholder}</option>`;
for (const { id, name } of options) {
$select.append(new Option(name, id));
}
}
fillSelect($province, getProvinces(), "Provincia");
$province.addEventListener("change", () => {
fillSelect($canton, getCantons($province.value), "Cantón");
fillSelect($district, [], "Distrito");
$canton.disabled = !$province.value;
$district.disabled = true;
});
$canton.addEventListener("change", () => {
fillSelect(
$district,
getDistricts($province.value, $canton.value),
"Distrito",
);
$district.disabled = !$canton.value;
});
</script>Si no usas un bundler, puedes importar directo desde node_modules con un
import map, o copiar dist/index.js (build ESM) a tu carpeta de assets
públicos.
Ejemplo con Laravel (Blade + Vite)
El paquete es JavaScript puro, así que en Laravel se usa del lado del
cliente: se instala con npm y se importa desde el JS que compila Vite
(resources/js/app.js o un archivo específico de la vista).
npm install @juniorov/cr-locations// resources/js/location.js
import { getProvinces, getCantons, getDistricts } from "@juniorov/cr-locations";
document.addEventListener("DOMContentLoaded", () => {
const $province = document.getElementById("province_id");
const $canton = document.getElementById("canton_id");
const $district = document.getElementById("district_id");
if (!$province) return;
const fill = ($select, options) => {
$select.innerHTML = '<option value="">Seleccione...</option>';
for (const { id, name } of options) {
$select.append(new Option(name, id));
}
};
fill($province, getProvinces());
$province.addEventListener("change", () => {
fill($canton, getCantons($province.value));
fill($district, []);
});
$canton.addEventListener("change", () => {
fill($district, getDistricts($province.value, $canton.value));
});
});{{-- resources/views/partials/location.blade.php --}}
<select name="province_id" id="province_id"></select>
<select name="canton_id" id="canton_id"></select>
<select name="district_id" id="district_id"></select>
@vite('resources/js/location.js')Registra resources/js/location.js como entrada en vite.config.js
(dentro de laravel-vite-plugin) junto a tu app.js habitual.
El formulario envía los mismos códigos que expone el paquete
(province_id, canton_id, district_id). Para validarlos en el backend
sin duplicar el catálogo en PHP, copia src/data/locations.json a
resources/data/ (o publícalo como asset) y valida contra ese JSON con una
regla Rule::in(...) construida a partir de sus claves.
Ejemplo con React (3 selects encadenados)
import { useState, useMemo } from "react";
import { getProvinces, getCantons, getDistricts } from "@juniorov/cr-locations";
function LocationSelect() {
const [provinceId, setProvinceId] = useState("");
const [cantonId, setCantonId] = useState("");
const [districtId, setDistrictId] = useState("");
const provinces = useMemo(() => getProvinces(), []);
const cantons = useMemo(() => getCantons(provinceId), [provinceId]);
const districts = useMemo(
() => getDistricts(provinceId, cantonId),
[provinceId, cantonId],
);
return (
<>
<select
value={provinceId}
onChange={(e) => {
setProvinceId(e.target.value);
setCantonId("");
setDistrictId("");
}}
>
<option value="">Provincia</option>
{provinces.map((p) => (
<option key={p.id} value={p.id}>{p.name}</option>
))}
</select>
<select
value={cantonId}
disabled={!provinceId}
onChange={(e) => {
setCantonId(e.target.value);
setDistrictId("");
}}
>
<option value="">Cantón</option>
{cantons.map((c) => (
<option key={c.id} value={c.id}>{c.name}</option>
))}
</select>
<select
value={districtId}
disabled={!cantonId}
onChange={(e) => setDistrictId(e.target.value)}
>
<option value="">Distrito</option>
{districts.map((d) => (
<option key={d.id} value={d.id}>{d.name}</option>
))}
</select>
</>
);
}API
| Función | Descripción |
| --- | --- |
| getProvinces() | Option[] — todas las provincias. |
| getCantons(provinceId) | Option[] — cantones de una provincia ([] si no existe). |
| getDistricts(provinceId, cantonId) | Option[] — distritos de un cantón ([] si no existe). |
| getProvinceName(provinceId) | string \| undefined. |
| getCantonName(provinceId, cantonId) | string \| undefined. |
| getDistrictName(provinceId, cantonId, districtId) | string \| undefined. |
| isValidProvince(provinceId) | boolean. |
| isValidCanton(provinceId, cantonId) | boolean. |
| isValidDistrict(provinceId, cantonId, districtId) | boolean. |
| searchDistricts(query) | District[] — busca distritos por nombre (sin distinguir mayúsculas/acentos). |
interface Option {
id: string;
name: string;
}
interface District {
id: string;
name: string;
provinceId: string;
cantonId: string;
}Los id son los códigos oficiales (provincia: "1"–"7"; cantón y distrito:
strings con ceros a la izquierda, ej. "01").
Desarrollo
npm install
npm run build # compila a dist/ (ESM + CJS + .d.ts)
npm test # build + tests con node:testPublicar
npm login
npm publish --access publicLicencia
MIT
