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

@jacksonavila/phone-lib

v2.0.10

Published

Librería JavaScript para input de teléfono con selector de país y banderas - Compatible con Vanilla JS y React

Readme

PhoneLib 📱

Modern JavaScript library to easily integrate a phone input with country selector, flags, and phone number validation. Compatible with Vanilla JavaScript and React.

Librería JavaScript moderna para integrar fácilmente un input de teléfono con selector de país, banderas y validación de números telefónicos. Compatible con Vanilla JavaScript y React.

npm version License: MIT


✨ Features / Características

  • Country dropdown / Dropdown de países showing name, ISO2 code, dial code, and flag
  • Tel input / Input tipo tel with automatic formatting based on selected country
  • Numbers only input / Input solo números - automatically filters non-numeric characters
  • Phone number validation / Validación de números using libphonenumber-js
  • Complete public API / API pública completa with methods to get number information
  • Vanilla JavaScript and React support / Soporte para Vanilla JavaScript y React
  • Two layouts available / Dos layouts disponibles: integrated and separated
  • Customizable events and callbacks / Eventos y callbacks personalizables
  • Full programmatic control / Control programático completo
  • Automatic country detection / Detección automática de país
  • Country filtering / Filtrado de países (include/exclude/disable)
  • Readonly/disabled mode / Modo readonly/disabled
  • Modern responsive CSS / Estilos CSS modernos y responsivos
  • Improved accessibility / Accesibilidad mejorada (ARIA labels, keyboard navigation)

📦 Installation / Instalación

Option 1: npm / Opción 1: npm

npm install @jacksonavila/phone-lib

Option 2: CDN (No npm required) / Opción 2: CDN (Sin npm)

Use directly from CDN / Usar directamente desde CDN - see Using from CDN / Usar desde CDN section below / ver sección abajo.

Dependencies / Dependencias

# For React projects / Para proyectos React
npm install react react-dom

# libphonenumber-js is installed automatically
# libphonenumber-js se instala automáticamente

🌐 Using from CDN / Usar desde CDN

You can use PhoneLib directly from CDN without npm / Puedes usar PhoneLib directamente desde CDN sin npm.

Method 1: Import Maps (Modern Browsers) / Método 1: Import Maps (Navegadores Modernos)

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jacksonavila/[email protected]/phone-lib.css">
</head>
<body>
  <div id="phone-container"></div>

  <script type="importmap">
    {
      "imports": {
        "@jacksonavila/phone-lib": "https://cdn.jsdelivr.net/npm/@jacksonavila/[email protected]/phone-lib.js",
        "libphonenumber-js": "https://esm.sh/[email protected]"
      }
    }
  </script>

  <script type="module">
    import PhoneLib from '@jacksonavila/phone-lib';

    const phoneLib = new PhoneLib('#phone-container', {
      initialCountry: 'CO',
      layout: 'integrated',
      showDialCode: true
    });
  </script>
</body>
</html>

CDN URLs / URLs de CDN:

Method 2: Script Tag (All Browsers) / Método 2: Script Tag (Todos los Navegadores)

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jacksonavila/[email protected]/phone-lib.css">
</head>
<body>
  <div id="phone-container"></div>

  <script src="https://cdn.jsdelivr.net/npm/@jacksonavila/[email protected]/phone-lib.cdn.js"></script>
  
  <script>
    let phoneLib = null;

    // Wait for PhoneLib to be ready / Esperar a que PhoneLib esté listo
    document.addEventListener('phoneLibReady', () => {
      phoneLib = new PhoneLib('#phone-container', {
        initialCountry: 'CO',
        layout: 'integrated',
        showDialCode: true
      });
    });

    // Handle errors / Manejar errores
    document.addEventListener('phoneLibError', (e) => {
      console.error('Error loading PhoneLib:', e.detail.error);
    });
  </script>
</body>
</html>

⚠️ Important / Importante: You need an HTTP server / Necesitas un servidor HTTP (doesn't work with file:// / no funciona con file://)

📖 Complete CDN guide / Guía completa de CDN: See USO-SIN-NPM.md / Ver USO-SIN-NPM.md


🚀 Quick Start / Inicio Rápido

Vanilla JavaScript

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="node_modules/@jacksonavila/phone-lib/phone-lib.css">
</head>
<body>
  <div id="phone-container"></div>

  <script type="module">
    import PhoneLib from '@jacksonavila/phone-lib';

    const phoneLib = new PhoneLib('#phone-container', {
      initialCountry: 'CO',
      layout: 'integrated',
      showDialCode: true
    });

    // Get number information / Obtener información del número
    const info = phoneLib.getInfo();
    console.log(info);
  </script>
</body>
</html>

React

import React from 'react';
import PhoneLibReact from '@jacksonavila/phone-lib/react';
import '@jacksonavila/phone-lib/css';

function App() {
  return (
    <PhoneLibReact
      initialCountry="CO"
      layout="integrated"
      showDialCode={true}
    />
  );
}

export default App;

📖 Complete Usage Guide / Guía de Uso Completa

Vanilla JavaScript

Basic Example / Ejemplo Básico

import PhoneLib from '@jacksonavila/phone-lib';
import '@jacksonavila/phone-lib/css';

const phoneLib = new PhoneLib('#phone-container', {
  initialCountry: 'CO',
  initialPhoneNumber: '+573001234567', // Optional: set initial phone number / Opcional: establecer número inicial
  preferredCountries: ['CO', 'US', 'ES'],
  showHint: true,
  layout: 'integrated',
  showDialCode: true
});

With Events and Callbacks / Con Eventos y Callbacks

import PhoneLib from '@jacksonavila/phone-lib';
import '@jacksonavila/phone-lib/css';

const phoneLib = new PhoneLib('#phone-container', {
  initialCountry: 'CO',
  
  // Callbacks
  onCountryChange: (country, dialCode, countryName) => {
    console.log('Country changed / País cambiado:', country, dialCode, countryName);
  },
  
  onPhoneChange: (phoneNumber, isValid, country) => {
    console.log('Number / Número:', phoneNumber, 'Valid / Válido:', isValid);
    if (isValid) {
      const info = phoneLib.getInfo();
      console.log('Complete info / Información completa:', info);
    }
  },
  
  onValidationChange: (isValid, phoneNumber) => {
    console.log('Validation / Validación:', isValid ? 'Valid / Válido' : 'Invalid / Inválido');
  },
  
  onFocus: () => console.log('Input focused / Input enfocado'),
  onBlur: () => console.log('Input blurred / Input perdió foco')
});

// Listen to custom DOM events / Escuchar eventos DOM personalizados
document.getElementById('phone-container').addEventListener('phoneLib:countryChange', (e) => {
  console.log('DOM event / Evento DOM:', e.detail);
});

Programmatic Control / Control Programático

// Set values / Establecer valores
phoneLib.setCountry('ES');
phoneLib.setPhoneNumber('+34600123456');
phoneLib.setValue('US', '5551234567');

// Control state / Controlar estado
phoneLib.enable();
phoneLib.disable();
phoneLib.reset();

// Get information / Obtener información
const country = phoneLib.getCountry();        // 'CO'
const dialCode = phoneLib.getDialCode();      // '+57'
const raw = phoneLib.getRaw();                // '3001234567'
const e164 = phoneLib.getE164();              // '+573001234567'
const isValid = phoneLib.isValid();           // true/false
const info = phoneLib.getInfo();              // Complete object / Objeto completo

Form Integration / Integración con Formularios

<form id="contact-form">
  <div id="phone-container"></div>
  <button type="submit">Submit / Enviar</button>
</form>

<script type="module">
  import PhoneLib from '@jacksonavila/phone-lib';
  import '@jacksonavila/phone-lib/css';

  const phoneLib = new PhoneLib('#phone-container', {
    initialCountry: 'CO',
    validateOnInput: true
  });

  document.getElementById('contact-form').addEventListener('submit', (e) => {
    e.preventDefault();
    
    const phoneInfo = phoneLib.getInfo();
    
    if (!phoneInfo.isValid) {
      alert('Please enter a valid number / Por favor ingrese un número válido');
      return;
    }

    // Send data / Enviar datos
    const formData = {
      phone: phoneInfo.e164,
      country: phoneInfo.country,
      // ... other fields / otros campos
    };

    console.log('Sending / Enviando:', formData);
  });
</script>

React

Basic Example / Ejemplo Básico

import React from 'react';
import PhoneLibReact from '@jacksonavila/phone-lib/react';
import '@jacksonavila/phone-lib/css';

function App() {
  return (
    <PhoneLibReact
      initialCountry="CO"
      layout="integrated"
      showDialCode={true}
    />
  );
}

export default App;

With Ref and Methods / Con Ref y Métodos

import React, { useRef } from 'react';
import PhoneLibReact from '@jacksonavila/phone-lib/react';
import '@jacksonavila/phone-lib/css';

function App() {
  const phoneLibRef = useRef(null);

  const handleSubmit = () => {
    const info = phoneLibRef.current.getInfo();
    
    if (!info.isValid) {
      alert('Invalid number / Número inválido');
      return;
    }

    console.log('Send / Enviar:', info.e164);
  };

  return (
    <div>
      <PhoneLibReact
        ref={phoneLibRef}
        initialCountry="CO"
        layout="integrated"
        onPhoneChange={(phone, isValid) => {
          console.log('Number / Número:', phone, 'Valid / Válido:', isValid);
        }}
      />
      <button onClick={handleSubmit}>Submit / Enviar</button>
    </div>
  );
}

With React State / Con Estado de React

import React, { useState, useRef } from 'react';
import PhoneLibReact from '@jacksonavila/phone-lib/react';
import '@jacksonavila/phone-lib/css';

function PhoneForm() {
  const phoneLibRef = useRef(null);
  const [phoneData, setPhoneData] = useState(null);

  const handleGetData = () => {
    const info = phoneLibRef.current.getInfo();
    setPhoneData(info);
  };

  return (
    <div>
      <PhoneLibReact
        ref={phoneLibRef}
        initialCountry="CO"
        onPhoneChange={(phone, isValid) => {
          if (isValid) {
            const info = phoneLibRef.current.getInfo();
            setPhoneData(info);
          }
        }}
      />
      
      {phoneData && (
        <div>
          <p>Country / País: {phoneData.country}</p>
          <p>Number / Número: {phoneData.e164}</p>
          <p>Valid / Válido: {phoneData.isValid ? 'Yes / Sí' : 'No'}</p>
        </div>
      )}
    </div>
  );
}

React Form Integration / Integración con Formularios React

import React, { useRef } from 'react';
import PhoneLibReact from '@jacksonavila/phone-lib/react';
import '@jacksonavila/phone-lib/css';

function ContactForm() {
  const phoneLibRef = useRef(null);
  const formRef = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    
    const phoneInfo = phoneLibRef.current.getInfo();
    
    if (!phoneInfo.isValid) {
      alert('Please enter a valid number / Por favor ingrese un número válido');
      return;
    }

    const formData = {
      name: formRef.current.name.value,
      email: formRef.current.email.value,
      phone: phoneInfo.e164,
      country: phoneInfo.country
    };

    // Send data / Enviar datos
    fetch('/api/contact', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(formData)
    });
  };

  return (
    <form ref={formRef} onSubmit={handleSubmit}>
      <input name="name" placeholder="Name / Nombre" required />
      <input name="email" type="email" placeholder="Email" required />
      
      <PhoneLibReact
        ref={phoneLibRef}
        initialCountry="CO"
        validateOnInput={true}
      />
      
      <button type="submit">Submit / Enviar</button>
    </form>
  );
}

With Initial Phone Number (React Forms) / Con Número Inicial (Formularios React)

Important / Importante: Use initialPhoneNumber to set an initial value and ensure the phone number persists when the parent component re-renders / Usa initialPhoneNumber para establecer un valor inicial y asegurar que el número persista cuando el componente padre se re-renderiza:

import React, { useState } from 'react';
import PhoneLibReact from '@jacksonavila/phone-lib/react';
import '@jacksonavila/phone-lib/css';

function EditContactForm({ contact }) {
  const [name, setName] = useState(contact?.name || '');
  const [email, setEmail] = useState(contact?.email || '');

  return (
    <form>
      <input 
        value={name} 
        onChange={(e) => setName(e.target.value)} 
        placeholder="Name / Nombre" 
      />
      <input 
        value={email} 
        onChange={(e) => setEmail(e.target.value)} 
        placeholder="Email" 
      />
      
      {/* The phone number value persists even when name/email change / 
          El valor del teléfono persiste incluso cuando cambian name/email */}
      <PhoneLibReact
        initialCountry={contact?.country || 'US'}
        initialPhoneNumber={contact?.phone || null}
        onPhoneChange={(phone, isValid) => {
          console.log('Phone / Teléfono:', phone);
        }}
      />
      
      <button type="submit">Save / Guardar</button>
    </form>
  );
}

💡 Why initialPhoneNumber is important / Por qué initialPhoneNumber es importante:

  • Prevents data loss / Previene pérdida de datos: Without initialPhoneNumber, the phone value can be lost when the parent component re-renders (e.g., when other form fields change) / Sin initialPhoneNumber, el valor del teléfono puede perderse cuando el componente padre se re-renderiza (ej: cuando otros campos del formulario cambian)
  • Form editing / Edición de formularios: Essential when editing existing data - the phone number is preserved during re-renders / Esencial al editar datos existentes - el número de teléfono se preserva durante re-renders
  • Controlled components / Componentes controlados: Works seamlessly with React's controlled component pattern / Funciona perfectamente con el patrón de componentes controlados de React

🎨 Available Layouts / Layouts Disponibles

Integrated Layout / Layout Integrado (Default)

The country selector and input are on the same line / El selector de país y el input están en la misma línea:

const phoneLib = new PhoneLib('#container', {
  layout: 'integrated',
  showDialCode: true  // Shows +57 in button / Muestra +57 en el botón
});

With code visible / Con código visible:

  • Shows / Muestra: [🇨🇴 +57 ▼] [300 123 4567]

Without code visible / Sin código visible:

const phoneLib = new PhoneLib('#container', {
  layout: 'integrated',
  showDialCode: false  // Only shows flag / Solo muestra la bandera
});
  • Shows / Muestra: [🇨🇴 ▼] [300 123 4567]

Separated Layout / Layout Separado

Fields are separated in a row / Los campos están separados en una fila:

const phoneLib = new PhoneLib('#container', {
  layout: 'separated',
  showDialCode: true  // Shows separate "Code" field / Muestra campo "Código" separado
});

With code visible / Con código visible:

  • Shows / Muestra: [Country / País: 🇨🇴 Colombia ▼] [Code / Código: +57] [Number / Número: 300 123 4567]

Without code visible / Sin código visible:

const phoneLib = new PhoneLib('#container', {
  layout: 'separated',
  showDialCode: false  // Only shows Country and Number / Solo muestra País y Número
});
  • Shows / Muestra: [Country / País: 🇨🇴 Colombia ▼] [Number / Número: 300 123 4567]

⚙️ Configuration Options / Opciones de Configuración

Basic Options / Opciones Básicas

{
  initialCountry: 'CO',              // Initial country / País inicial (ISO2)
  initialPhoneNumber: '+573001234567', // Initial phone number (optional) / Número inicial (opcional)
  preferredCountries: ['CO', 'US'],  // Countries that appear first / Países que aparecen primero
  showHint: true,                    // Show validation hint / Mostrar hint de validación
  layout: 'integrated',              // 'integrated' or 'separated' / 'integrated' o 'separated'
  showDialCode: true                 // Show dial code / Mostrar código de marcación
}

📝 Note about initialPhoneNumber / Nota sobre initialPhoneNumber:

  • Vanilla JS: Use initialPhoneNumber in the constructor options to set an initial phone number value / Usa initialPhoneNumber en las opciones del constructor para establecer un valor inicial del teléfono
  • React: Use the initialPhoneNumber prop to set an initial value. This prop also ensures the phone number value persists when the parent component re-renders / Usa la prop initialPhoneNumber para establecer un valor inicial. Esta prop también asegura que el valor del teléfono persista cuando el componente padre se re-renderiza
  • The value is preserved during re-renders, preventing data loss in React forms / El valor se preserva durante re-renders, previniendo pérdida de datos en formularios React

Advanced Options / Opciones Avanzadas

{
  // Initial values / Valores iniciales
  initialCountry: 'CO',                // Initial country (ISO2) / País inicial (ISO2)
  initialPhoneNumber: '+573001234567', // Initial phone number (optional) / Número inicial (opcional)
                                      // In React: ensures value persists during re-renders / 
                                      // En React: asegura que el valor persista durante re-renders
  
  // Detection and validation / Detección y validación
  autoDetectCountry: true,            // Auto-detect country / Detectar país automáticamente
  validateOnInput: false,             // Validate while typing / Validar mientras se escribe
  
  // Country filtering / Filtrado de países
  onlyCountries: ['CO', 'US', 'ES'],  // Only these countries / Solo estos países
  disabledCountries: ['CU', 'KP'],    // Disable these / Deshabilitar estos
  excludeCountries: ['XX'],           // Exclude these / Excluir estos
  
  // States / Estados
  readonly: false,                   // Read-only mode / Modo solo lectura
  disabled: false,                   // Disabled component / Componente deshabilitado
  
  // Customization / Personalización
  placeholder: 'Enter your number',   // Custom placeholder / Placeholder personalizado
  countryLabel: 'Country',            // Label for selector / Label para selector
  dialCodeLabel: 'Code',             // Label for code / Label para código
  phoneLabel: 'Phone number',         // Label for number / Label para número
  
  // Messages / Mensajes
  messages: {
    invalid: 'Invalid number',
    valid: '✓ Valid number'
  },
  
  // Width control / Control de anchos
  width: '500px',              // Wrapper width / Ancho del wrapper
  maxWidth: '100%',            // Max width / Ancho máximo
  dropdownWidth: '150px',      // Country selector width (integrated) / Ancho selector (integrado)
  inputWidth: '350px',         // Phone input width (integrated) / Ancho input (integrado)
  gridColumns: '3fr 1fr 4fr',  // Grid columns (separated) / Columnas grid (separado)
  countryWidth: '250px',       // Country field width (separated) / Ancho campo país (separado)
  dialCodeWidth: '100px',      // Dial code width (separated) / Ancho código (separado)
  phoneWidth: '350px',         // Phone field width (separated) / Ancho campo teléfono (separado)
  
  // Arrow icon / Icono de flecha
  arrowIcon: null,  // Custom arrow HTML (SVG, emoji, image) / HTML personalizado para flecha
  
  // Styles / Estilos
  customClasses: {
    wrapper: 'my-class',
    input: 'my-input'
  },
  customStyles: {
    input: {
      borderColor: '#4a90e2'
    }
  }
}

Callbacks and Events / Callbacks y Eventos

{
  onCountryChange: (country, dialCode, countryName) => {
    // Country changed / País cambiado
  },
  onPhoneChange: (phoneNumber, isValid, country) => {
    // Number changed / Número cambiado
  },
  onValidationChange: (isValid, phoneNumber) => {
    // Validation changed / Validación cambiada
  },
  onFocus: () => {
    // Input focused / Input enfocado
  },
  onBlur: () => {
    // Input blurred / Input perdió foco
  }
}

📚 Public API

Reading Methods / Métodos de Lectura

getCountry()

Returns the ISO2 code of the selected country / Devuelve el código ISO2 del país seleccionado.

const country = phoneLib.getCountry(); // 'CO'

getDialCode()

Returns the dial code of the selected country / Devuelve el código de marcación del país seleccionado.

const dialCode = phoneLib.getDialCode(); // '+57'

getRaw()

Returns the entered number without formatting (digits only) / Devuelve el número ingresado sin formato (solo dígitos).

const raw = phoneLib.getRaw(); // '3001234567'

getE164()

Returns the number in E.164 format / Devuelve el número en formato E.164.

const e164 = phoneLib.getE164(); // '+573001234567'

isValid()

Returns true if the number is valid, false otherwise / Devuelve true si el número es válido, false en caso contrario.

const isValid = phoneLib.isValid(); // true o false

formatInternational()

Returns the number in international format / Devuelve el número en formato internacional.

const international = phoneLib.formatInternational(); // '+57 300 123 4567'

formatNational()

Returns the number in national format / Devuelve el número en formato nacional.

const national = phoneLib.formatNational(); // '300 123 4567'

formatRFC3966()

Returns the number in RFC3966 format / Devuelve el número en formato RFC3966.

const rfc3966 = phoneLib.formatRFC3966(); // 'tel:+57-300-123-4567'

getNumberType()

Returns the number type (MOBILE, FIXED_LINE, etc.) / Devuelve el tipo de número (MOBILE, FIXED_LINE, etc.).

const type = phoneLib.getNumberType(); // 'MOBILE' o null

getInfo()

Returns an object with all number information / Devuelve un objeto con toda la información del número.

const info = phoneLib.getInfo();
// {
//   country: 'CO',
//   dialCode: '+57',
//   raw: '3001234567',
//   e164: '+573001234567',
//   international: '+57 300 123 4567',
//   national: '300 123 4567',
//   rfc3966: 'tel:+57-300-123-4567',
//   isValid: true,
//   type: 'MOBILE',
//   countryName: 'Colombia'
// }

getCountryMetadata()

Returns complete information about the selected country / Devuelve información completa del país seleccionado.

const metadata = phoneLib.getCountryMetadata();
// {
//   iso2: 'CO',
//   name: 'Colombia',
//   dialCode: '+57',
//   flag: '<img...>'
// }

Control Methods / Métodos de Control

setCountry(iso2)

Sets the country programmatically / Establece el país programáticamente.

phoneLib.setCountry('ES');

setPhoneNumber(number)

Sets the phone number programmatically / Establece el número telefónico programáticamente.

phoneLib.setPhoneNumber('+34600123456');

setValue(country, number)

Sets both country and number / Establece país y número juntos.

phoneLib.setValue('ES', '600123456');

enable() / disable()

Enables or disables the component / Habilita o deshabilita el componente.

phoneLib.enable();
phoneLib.disable();

reset()

Resets the component to initial values / Resetea el componente a valores iniciales.

phoneLib.reset();

destroy()

Destroys the instance and cleans up resources / Destruye la instancia y limpia recursos.

phoneLib.destroy();

updateOptions(newOptions)

Updates options dynamically / Actualiza opciones dinámicamente.

phoneLib.updateOptions({
  preferredCountries: ['CO', 'US', 'ES', 'MX']
});

🎨 Custom Styling / Estilos Personalizados

With CSS Classes / Con Clases CSS

const phoneLib = new PhoneLib('#container', {
  customClasses: {
    wrapper: 'my-custom-class',
    dropdownButton: 'my-custom-button',
    input: 'my-custom-input'
  }
});

With Inline Styles / Con Estilos Inline

const phoneLib = new PhoneLib('#container', {
  customStyles: {
    dropdownButton: {
      backgroundColor: '#4a90e2',
      borderRadius: '20px',
      color: 'white'
    },
    input: {
      borderColor: '#4a90e2',
      fontSize: '18px'
    }
  }
});

Custom Arrow Icon / Icono de Flecha Personalizado

const phoneLib = new PhoneLib('#container', {
  // Opción 1: SVG personalizado
  arrowIcon: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12">
    <path d="M3 4.5 L6 7.5 L9 4.5" stroke="#333" stroke-width="2" fill="none"/>
  </svg>`,
  
  // Opción 2: Emoji
  arrowIcon: '▼',
  
  // Opción 3: Imagen
  arrowIcon: '<img src="arrow.png" alt="▼" style="width: 12px; height: 12px;">'
});

Nota: Si no se especifica arrowIcon, se usa un chevron SVG por defecto.

Customizable Elements / Elementos Personalizables

  • wrapper - Main container / Contenedor principal
  • dropdownButton - Country selector button / Botón del selector de país
  • input - Phone input field / Campo de entrada de teléfono
  • dialCodeInput - Dial code field (separated layout only) / Campo de código (solo layout separado)
  • row - Grid row (separated layout only) / Fila del grid (solo layout separado)
  • arrowIcon - Dropdown arrow icon / Icono de flecha del dropdown

🔧 Advanced Examples / Ejemplos Avanzados

Automatic Country Detection / Detección Automática de País

const phoneLib = new PhoneLib('#container', {
  autoDetectCountry: true  // Detects country when entering +34... / Detecta país al ingresar +34...
});

// User types / Usuario escribe: +34 600 123 456
// Automatically changes to Spain / Automáticamente cambia a España

Country Filtering / Filtrado de Países

const phoneLib = new PhoneLib('#container', {
  // Only show these countries / Solo mostrar estos países
  onlyCountries: ['CO', 'US', 'ES', 'MX'],
  
  // Disable these countries (appear but can't be selected) / Deshabilitar estos países
  disabledCountries: ['CU', 'KP'],
  
  // Exclude these countries (don't appear in list) / Excluir estos países
  excludeCountries: ['XX']
});

Real-time Validation / Validación en Tiempo Real

const phoneLib = new PhoneLib('#container', {
  validateOnInput: true,  // Validate while user types / Valida mientras el usuario escribe
  
  onValidationChange: (isValid) => {
    if (isValid) {
      console.log('Valid number! / ¡Número válido!');
    }
  }
});

Readonly/Disabled Mode / Modo Readonly/Disabled

// Read-only / Solo lectura
const phoneLib = new PhoneLib('#container', {
  readonly: true
});

// Disabled / Deshabilitado
const phoneLib = new PhoneLib('#container', {
  disabled: true
});

📱 React Component Props

| Prop | Type | Default | Description / Descripción | |------|------|---------|--------------------------| | initialCountry | string | 'US' | Initial country (ISO2) / País inicial (ISO2) | | initialPhoneNumber | string | null | null | Initial phone number value. Important: This prop ensures the phone value persists during parent component re-renders in React / Valor inicial del teléfono. Importante: Esta prop asegura que el valor del teléfono persista durante re-renders del componente padre en React | | preferredCountries | array | [] | Preferred countries / Países preferidos | | showHint | boolean | true | Show validation hint / Mostrar hint de validación | | layout | string | 'integrated' | 'integrated' or 'separated' / 'integrated' o 'separated' | | showDialCode | boolean | true | Show dial code / Mostrar código de marcación | | autoDetectCountry | boolean | false | Auto-detect country / Detectar país automáticamente | | validateOnInput | boolean | false | Validate while typing / Validar mientras se escribe | | disabledCountries | array | [] | Disabled countries / Países deshabilitados | | onlyCountries | array | [] | Only these countries / Solo estos países | | excludeCountries | array | [] | Exclude these countries / Excluir estos países | | readonly | boolean | false | Read-only mode / Modo solo lectura | | disabled | boolean | false | Disabled component / Componente deshabilitado | | placeholder | string | null | Custom placeholder / Placeholder personalizado | | countryLabel | string | 'Country' / 'País' | Label for selector / Label para selector | | dialCodeLabel | string | 'Code' / 'Código' | Label for code / Label para código | | phoneLabel | string | 'Phone number' / 'Número de teléfono' | Label for number / Label para número | | arrowIcon | string | null | Custom arrow HTML (SVG, emoji, image) / HTML personalizado para flecha | | customClasses | object | {} | Custom CSS classes / Clases CSS personalizadas | | customStyles | object | {} | Inline styles / Estilos inline personalizados | | width | string | null | Wrapper width (e.g., '500px', '100%') / Ancho del wrapper | | maxWidth | string | null | Max wrapper width / Ancho máximo del wrapper | | dropdownWidth | string | null | Country selector width (integrated) / Ancho selector (integrado) | | inputWidth | string | null | Phone input width (integrated) / Ancho input (integrado) | | gridColumns | string | null | Grid columns (separated, e.g., '3fr 1fr 4fr') / Columnas grid (separado) | | countryWidth | string | null | Country field width (separated) / Ancho campo país (separado) | | dialCodeWidth | string | null | Dial code width (separated) / Ancho código (separado) | | phoneWidth | string | null | Phone field width (separated) / Ancho campo teléfono (separado) | | messages | object | {} | Custom messages / Mensajes personalizables | | ariaLabels | object | {} | ARIA labels / Labels ARIA personalizables | | onCountryChange | function | null | Callback when country changes / Callback cuando cambia el país | | onPhoneChange | function | null | Callback when number changes / Callback cuando cambia el número | | onValidationChange | function | null | Callback when validation changes / Callback cuando cambia la validación | | onFocus | function | null | Callback when focused / Callback cuando se enfoca | | onBlur | function | null | Callback when blurred / Callback cuando pierde foco |


🧪 Development and Testing / Desarrollo y Pruebas

Run Demos Locally / Ejecutar Demos Localmente

# Install dependencies / Instalar dependencias
npm install

# Start development server / Iniciar servidor de desarrollo
npm run serve

This will open http://localhost:3004 with all available demos / Esto abrirá http://localhost:3004 con todos los demos disponibles.

Demo Files / Archivos de Demo

  • demo.html - Basic integrated layout / Layout integrado básico
  • demo-separated.html - Separated layout / Layout separado
  • demo-all-layouts.html - All layouts comparison / Comparación de todos los layouts
  • demo-features.html - All features / Todas las características
  • demo-react.html - React example / Ejemplo con React
  • demo-cdn-importmap.html - CDN with Import Maps / CDN con Import Maps
  • demo-cdn-script.html - CDN with Script Tag / CDN con Script Tag
  • demo-widths.html - Width control examples / Ejemplos de control de anchos

📦 Package Structure / Estructura del Paquete

@jacksonavila/phone-lib/
├── phone-lib.js          # Main code (Vanilla JS) / Código principal (Vanilla JS)
├── phone-lib.css         # CSS styles / Estilos CSS
├── phone-lib-react.jsx   # React component / Componente React
├── phone-lib-react.js    # CommonJS/ESM React version / Versión CommonJS/ESM React
└── README.md             # Documentation / Documentación

Import Paths / Rutas de Importación

// Main library (Vanilla JS) / Librería principal (Vanilla JS)
import PhoneLib from '@jacksonavila/phone-lib';

// React component / Componente React
import PhoneLibReact from '@jacksonavila/phone-lib/react';

// CSS styles / Estilos CSS
import '@jacksonavila/phone-lib/css';

// Or with full paths / O con rutas completas
import PhoneLib from '@jacksonavila/phone-lib/phone-lib.js';
import PhoneLibReact from '@jacksonavila/phone-lib/phone-lib-react.jsx';
import '@jacksonavila/phone-lib/phone-lib.css';

🤝 Contributing / Contribuir

Contributions are welcome / Las contribuciones son bienvenidas. Please / Por favor:

  1. Fork the project / Haz fork del proyecto
  2. Create a feature branch / Crea una rama para tu feature (git checkout -b feature/AmazingFeature)
  3. Commit your changes / Commit tus cambios (git commit -m 'Add some AmazingFeature')
  4. Push to the branch / Push a la rama (git push origin feature/AmazingFeature)
  5. Open a Pull Request / Abre un Pull Request

📄 License / Licencia

This project is licensed under the MIT License / Este proyecto está bajo la Licencia MIT - see the LICENSE file for details / ver el archivo LICENSE para más detalles.


🙏 Acknowledgments / Agradecimientos

  • libphonenumber-js - For phone number validation and formatting / Para validación y formato de números telefónicos

📞 Support / Soporte

If you have questions or find any issues / Si tienes preguntas o encuentras algún problema:


Made with ❤️ for the developer community / Hecho con ❤️ para la comunidad de desarrolladores