Cómo acceder a los contactos desde la libreta de direcciones

A veces, quieres permitir que los usuarios de tu app seleccionen uno de sus contactos para enviarles mensajes a través de un correo electrónico o una aplicación de chat, o ayudarlos a descubrir cuáles de sus contactos ya se unieron a una plataforma social.

A la manera moderna

Cómo usar la API de Contact Picker

Para obtener contactos de la libreta de direcciones, debes usar la API de selector de contactos, que les permite a los usuarios seleccionar entradas de su lista de contactos y compartir detalles limitados de las entradas seleccionadas con tu app. Hay varias propiedades disponibles, como name, email, tel, address y icon. Para obtener información sobre las propiedades concretas, llama a navigator.contacts.getProperties(). Para permitir que el usuario seleccione varios contactos, pasa {multiple: true} como el segundo parámetro de navigator.contacts.select().

Navegadores compatibles

  • x
  • x
  • x
  • x

Origen

La API de Contact Picker está disponible en la versión de Chrome para Android a partir de la versión 80.

El método clásico

Con un formulario normal

El método de resguardo consiste en usar un formulario normal que le permite al usuario ingresar los detalles del contacto.

Navegadores compatibles

  • 1
  • 12
  • 1
  • ≤4

Origen

Mejora progresiva

Si se admite la API de Contact Picker, oculta los campos estáticos del formulario y muestra un botón de selección en su lugar.

const button = document.querySelector('button');
const name = document.querySelector('.name');
const address = document.querySelector('.address');
const email = document.querySelector('.email');
const tel = document.querySelector('.tel');
const pre = document.querySelector('pre');
const autofills = document.querySelectorAll('.autofill');

if ('contacts' in navigator) {
  button.hidden = false;
  for (const autofill of autofills) {
    autofill.parentElement.style.display = 'none';
  }
  address.parentElement.style.display = 'block';
  button.addEventListener('click', async () => {
    const props = ['name', 'email', 'tel', 'address'];
    const opts = { multiple: false };
    try {
      const [contact] = await navigator.contacts.select(props, opts);
      name.value = contact.name;
      address.value = contact.address;
      tel.value = contact.tel;
      email.value = contact.email;
    } catch (err) {
      pre.textContent = `${err.name}: ${err.message}`;
    }
  });
}

Lecturas adicionales

Demostración

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="icon"
      href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🎉</text></svg>"
    />
    <title>How to access contacts from the address book</title>
  </head>
  <body>
    <h1>How to access contacts from the address book</h1>

    <p>Ship your order as a present to a friend.</p>
    <button hidden type="button">Open address book</button>
    <pre></pre>

    <label> Name <input class="name" autocomplete="name"></label>

    <label hidden>Address <input class="address" required></label>

    <label>Street <input class="autofill" autocomplete="address-line1" required></label>

    <label>City <input class="autofill" autocomplete="address-level2" required></label>

    <label>State / Province / Region (optional) <input class="autofill" autocomplete="address-level1"></label>

    <label>ZIP / Postal code (optional) <input class="autofill" autocomplete="postal-code"></label>

    <label>Country <input class="autofill" autocomplete="country"></label>

    <label>Email<input class="email" autocomplete="email"></label>

    <label>Telephone<input class="tel" autocomplete="tel"></label>
  </body>
</html>

CSS


        html {
  box-sizing: border-box;
  font-family: system-ui, sans-serif;
  color-scheme: dark light;
}

*, *:before, *:after {
  box-sizing: inherit;
}

body {
  margin: 1rem;
}

input {
  display: block;
  margin-block-end: 1rem;
}
        

JS


        const button = document.querySelector('button');
const name = document.querySelector('.name')
const address = document.querySelector('.address')
const email = document.querySelector('.email')
const tel = document.querySelector('.tel')
const pre = document.querySelector('pre')
const autofills = document.querySelectorAll('.autofill')

if ('contacts' in navigator) {
  button.hidden = false;
  for (const autofill of autofills) {
    autofill.parentElement.style.display = 'none'
  }
  address.parentElement.style.display = 'block';
  button.addEventListener('click', async () => {
    const props = ['name', 'email', 'tel', 'address'];
    const opts = {multiple: false};
    try {
      const [contact] = await navigator.contacts.select(props, opts);
      name.value = contact.name;
      address.value = contact.address;
      tel.value = contact.tel
      email.value = contact.email;
    } catch (err) {
      pre.textContent = `${err.name}: ${err.message}`
    }
  });
}