Documentación de la API - Endpoints y Ejemplos

Formulario de Dirección con Selects en Cascada

Construye formularios de dirección profesionales con selects en cascada de país, estado y ciudad

Aprende a construir un formulario de dirección completo con dropdowns de país → estado → ciudad usando los endpoints select de CountryDataAPI.

Descripción General

Esta guía te muestra cómo crear inputs de select en cascada para:

  • Selección de país - Cargar todos los países disponibles
  • Selección de estado/provincia - Filtrado por país seleccionado
  • Selección de ciudad - Filtrado por estado seleccionado

Los endpoints select están optimizados para formularios, devolviendo solo los campos id y name para un tamaño de payload mínimo y máximo rendimiento.

Requisitos Previos

  • Una clave API de CountryDataAPI (Consigue una aquí)
  • Conocimientos básicos de JavaScript y HTML
  • Navegador web moderno con soporte para fetch API

Paso 1: Cargar Países

Primero, carga todos los países cuando tu página cargue. Los países rara vez cambian, así que puedes cachear estos datos en localStorage para mejor rendimiento.

const API_KEY = 'your-api-key';
const BASE_URL = 'https://api.countrydataapi.com/v1';

async function loadCountries() {
  try {
    const response = await fetch(
      `${BASE_URL}/select/countries?apikey=${API_KEY}&lang=es`
    );
    const { success, data, error } = await response.json();

    if (!success) {
      console.error('Error de API:', error);
      return;
    }

    const countrySelect = document.getElementById('country');
    data.forEach(country => {
      const option = new Option(country.name, country.id);
      countrySelect.add(option);
    });
  } catch (err) {
    console.error('Error de Red:', err);
  }
}

// Llamar al cargar la página
document.addEventListener('DOMContentLoaded', loadCountries);

Consejo: Cachea la lista de países en localStorage para evitar llamadas repetidas a la API. ¡Los países no cambian frecuentemente!

Paso 2: Cargar Estados Cuando Cambie el País

Cuando un usuario seleccione un país, carga los estados/provincias correspondientes y resetea el dropdown de ciudad.

document.getElementById('country').addEventListener('change', async (e) => {
  const countryId = e.target.value;
  const stateSelect = document.getElementById('state');
  const citySelect = document.getElementById('city');

  // Resetear dropdowns de estado y ciudad
  stateSelect.innerHTML = '<option value="">Selecciona estado...</option>';
  citySelect.innerHTML = '<option value="">Selecciona ciudad...</option>';
  stateSelect.disabled = true;
  citySelect.disabled = true;

  if (!countryId) return;

  try {
    const response = await fetch(
      `${BASE_URL}/select/states?apikey=${API_KEY}&country=${countryId}&lang=es`
    );
    const { success, data, error } = await response.json();

    if (!success) {
      console.error('Error de API:', error);
      return;
    }

    data.forEach(state => {
      stateSelect.add(new Option(state.name, state.id));
    });

    stateSelect.disabled = false;
  } catch (err) {
    console.error('Error de Red:', err);
  }
});

Paso 3: Cargar Ciudades Cuando Cambie el Estado

Finalmente, carga las ciudades cuando se seleccione un estado.

document.getElementById('state').addEventListener('change', async (e) => {
  const stateId = e.target.value;
  const citySelect = document.getElementById('city');

  // Resetear dropdown de ciudad
  citySelect.innerHTML = '<option value="">Selecciona ciudad...</option>';
  citySelect.disabled = true;

  if (!stateId) return;

  try {
    const response = await fetch(
      `${BASE_URL}/select/cities?apikey=${API_KEY}&state=${stateId}&lang=es`
    );
    const { success, data, error } = await response.json();

    if (!success) {
      console.error('Error de API:', error);
      return;
    }

    data.forEach(city => {
      citySelect.add(new Option(city.name, city.id));
    });

    citySelect.disabled = false;
  } catch (err) {
    console.error('Error de Red:', err);
  }
});

Ejemplo Completo de HTML

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Formulario de Dirección - CountryDataAPI</title>
  <style>
    body {
      font-family: system-ui, -apple-system, sans-serif;
      max-width: 600px;
      margin: 50px auto;
      padding: 20px;
    }
    .form-group {
      margin-bottom: 20px;
    }
    label {
      display: block;
      margin-bottom: 8px;
      font-weight: 600;
      color: #333;
    }
    select {
      width: 100%;
      padding: 10px;
      border: 2px solid #e2e8f0;
      border-radius: 6px;
      font-size: 16px;
      background-color: white;
      cursor: pointer;
    }
    select:disabled {
      background-color: #f7fafc;
      cursor: not-allowed;
      opacity: 0.6;
    }
    select:focus {
      outline: none;
      border-color: #3b82f6;
    }
    button {
      background-color: #3b82f6;
      color: white;
      padding: 12px 24px;
      border: none;
      border-radius: 6px;
      font-size: 16px;
      font-weight: 600;
      cursor: pointer;
      width: 100%;
    }
    button:disabled {
      background-color: #cbd5e0;
      cursor: not-allowed;
    }
  </style>
</head>
<body>
  <h1>Formulario de Dirección</h1>

  <form id="address-form">
    <div class="form-group">
      <label for="country">País *</label>
      <select id="country" name="country" required>
        <option value="">Selecciona país...</option>
      </select>
    </div>

    <div class="form-group">
      <label for="state">Estado/Provincia *</label>
      <select id="state" name="state" required disabled>
        <option value="">Selecciona estado...</option>
      </select>
    </div>

    <div class="form-group">
      <label for="city">Ciudad *</label>
      <select id="city" name="city" required disabled>
        <option value="">Selecciona ciudad...</option>
      </select>
    </div>

    <div class="form-group">
      <label for="street">Dirección *</label>
      <input type="text" id="street" name="street" required
             style="width: 100%; padding: 10px; border: 2px solid #e2e8f0; border-radius: 6px;">
    </div>

    <button type="submit">Enviar Dirección</button>
  </form>

  <script src="address-form.js"></script>
</body>
</html>

Envío del Formulario

Maneja el envío del formulario para obtener los valores seleccionados:

document.getElementById('address-form').addEventListener('submit', (e) => {
  e.preventDefault();

  const formData = new FormData(e.target);
  const address = {
    country: formData.get('country'),
    state: formData.get('state'),
    city: formData.get('city'),
    street: formData.get('street')
  };

  console.log('Dirección enviada:', address);

  // Enviar a tu backend o procesar según necesites
  // fetch('/api/save-address', {
  //   method: 'POST',
  //   headers: { 'Content-Type': 'application/json' },
  //   body: JSON.stringify(address)
  // });
});

Uso de Tokens

Esta implementación es altamente eficiente con el uso de tokens:

  • 1 token para cargar países (una vez por carga de página, puede cachearse)
  • 1 token por búsqueda de estado (cuando el usuario selecciona un país)
  • 1 token por búsqueda de ciudad (cuando el usuario selecciona un estado)

Ejemplo: Un usuario completando el formulario usa solo 3 tokens en total.

Consejos de Optimización

1. Cachear Datos de Países

Los países no cambian a menudo. Cachéalos en localStorage:

async function loadCountries() {
  const cached = localStorage.getItem('countries');

  if (cached) {
    const data = JSON.parse(cached);
    populateCountrySelect(data);
    return;
  }

  const response = await fetch(
    `${BASE_URL}/select/countries?apikey=${API_KEY}&lang=es`
  );
  const { success, data } = await response.json();

  if (success) {
    localStorage.setItem('countries', JSON.stringify(data));
    populateCountrySelect(data);
  }
}

function populateCountrySelect(countries) {
  const select = document.getElementById('country');
  countries.forEach(country => {
    select.add(new Option(country.name, country.id));
  });
}

2. Agregar Estados de Carga

Muestra retroalimentación visual mientras se cargan los datos:

async function loadStates(countryId) {
  const stateSelect = document.getElementById('state');
  stateSelect.innerHTML = '<option>Cargando...</option>';
  stateSelect.disabled = true;

  // ... fetch states

  stateSelect.disabled = false;
}

3. Debounce en Input de Búsqueda

Si agregas un dropdown con búsqueda, aplica debounce al input:

let debounceTimer;
searchInput.addEventListener('input', (e) => {
  clearTimeout(debounceTimer);
  debounceTimer = setTimeout(() => {
    filterOptions(e.target.value);
  }, 300);
});

4. Manejar Errores con Gracia

Siempre proporciona mensajes de error amigables para el usuario:

try {
  // Llamada API
} catch (err) {
  const select = document.getElementById('state');
  select.innerHTML = '<option>Error al cargar estados. Intenta de nuevo.</option>';
}

Soporte Multi-idioma

La API soporta múltiples idiomas. Cambia el parámetro lang:

// Español
`${BASE_URL}/select/countries?apikey=${API_KEY}&lang=es`

// Portugués
`${BASE_URL}/select/countries?apikey=${API_KEY}&lang=pt`

// Francés
`${BASE_URL}/select/countries?apikey=${API_KEY}&lang=fr`

// Alemán
`${BASE_URL}/select/countries?apikey=${API_KEY}&lang=de`

// Italiano
`${BASE_URL}/select/countries?apikey=${API_KEY}&lang=it`

Próximos Pasos

¿Necesitas Ayuda?

Si tienes preguntas o necesitas asistencia:


Consejo Pro: Para aplicaciones en producción, considera implementar un componente de dropdown personalizado con funcionalidad de búsqueda para manejar países con muchos estados/ciudades. Librerías como Select2, Choices.js, o autocompletar personalizado pueden mejorar significativamente la UX.