Controles de Autocompletar Ligeros con la Lista de Datos HTML5

En este tutorial, profundizaremos en el poco utilizado elemento HTML5 <datalist>. Puede implementar un control de formulario de autocompletar ligero, accesible y compatible con navegadores que no requiere JavaScript.

¿Qué sucede con <select>?

Los controles HTML5 <select> son ideales cuando deseas que el usuario elija entre un rango pequeño de opciones. Son menos prácticos cuando:

  • hay muchas opciones, como países o títulos de trabajo
  • el usuario desea ingresar su propia opción que no está en la lista

La solución obvia es un control de autocompletar. Esto permite al usuario ingresar algunos caracteres, lo que limita las opciones disponibles para una selección más rápida.

<select> saltará a la ubicación correcta a medida que comiences a escribir, pero eso no siempre es evidente. No funcionará en todos los dispositivos (como pantallas táctiles) y se reinicia en un segundo o dos.

Los desarrolladores a menudo recurren a una de las muchas soluciones potenciadas por JavaScript, pero un control de autocompletar personalizado no siempre es necesario. El elemento HTML5 <datalist> es ligero, accesible y no tiene dependencias de JavaScript. Puede que hayas escuchado que es problemático o carece de soporte. Eso no es cierto en 2021, pero hay inconsistencias y advertencias entre los navegadores.

<datalist> Inicio Rápido

Seleccionar su país de una lista con más de 200 opciones es un candidato ideal para un control de autocompletar. Defina un <datalist> con elementos secundarios <option> para cada país directamente en una página HTML:

<datalist id="countrydata">
  <option>Afghanistan</option>
  <option>Åland Islands</option>
  <option>Albania</option>
  <option>Algeria</option>
  <option>American Samoa</option>
  <option>Andorra</option>
  <option>Angola</option>
  <option>Anguilla</option>
  <option>Antarctica</option>
  ...etc...
</datalist>

El id del datalist puede entonces ser referenciado por un atributo list en cualquier campo <input>:

<label for="country">country</label>

<input type="text"
  list="countrydata"
  id="country" name="country"
  size="50"
  autocomplete="off" />

Confusamente, es mejor establecer autocomplete="off". Esto asegura que se muestren los valores en el <datalist> pero no los valores que el usuario ingresó previamente en el navegador.

El resultado:

Esta es la representación predeterminada en Microsoft Edge. Otros aplicativos implementan funcionalidad similar, pero el aspecto difiere entre plataformas y navegadores.

<option> Opciones

Usar la etiqueta como un texto hijo de un <option> es común:

<datalist id="mylist">
  <option>label one</option>
  <option>label two</option>
  <option>label three</option>
</datalist>

Usar un atributo value produce resultados idénticos:

<datalist id="mylist">
  <option value="label one" />
  <option value="label two" />
  <option value="label three" />
</datalist>

Nota: la barra diagonal de cierre /> es opcional en HTML5, aunque podría ayudar a prevenir errores de codificación.

También puede establecer un valor según una etiqueta elegida utilizando cualquiera de los siguientes formatos.

Opción 1:

<datalist id="mylist">
  <option value="1">label one</option>
  <option value="2">label two</option>
  <option value="3">label three</option>
</datalist>

Opción 2:

<datalist id="mylist">
  <option value="1" label="label one" />
  <option value="2" label="label two" />
  <option value="3" label="label three" />
</datalist>

En ambos casos, el campo de entrada se establece en 1, 2 o 3 cuando se elige una opción válida, pero la IU varía entre navegadores:

  • Chrome muestra una lista con tanto el valor como la etiqueta. Solo queda el valor una vez que se elige una opción.
  • Firefox muestra una lista con la etiqueta únicamente. Cambia al valor una vez que se elige una opción.
  • Edge muestra solo el valor.

El siguiente ejemplo de CodePen muestra todas las variaciones:

Ver el Pen
Ejemplos de autocompletado en HTML5 <datalist>
por SitePoint (@SitePoint)
en CodePen.

Las implementaciones evolucionarán, pero por ahora, les aconsejo que no utilicen un valor y una etiqueta ya que es probable que confunda a los usuarios. (Se discute una solución alternativa más abajo.)

<datalist> Soporte de navegadores y alternativas

El elemento <datalist> cuenta con un buen soporte en navegadores modernos así como en Internet Explorer 10 y 11:

Hay varias notas de implementación, pero no afectarán la mayoría de los usos. Lo peor que podría pasar es que un campo vuelva a ser un texto de entrada estándar.

Si es imperativo soportar IE9 y versiones inferiores, existe un patrón de respaldo que utiliza un <select> estándar en conjunto con una entrada de texto cuando el <datalist> falla. Adaptando el ejemplo de país:

<label for="country">country</label>

<datalist id="countrydata">

  <select name="countryselect">
    <option></option>
    <option>Afghanistan</option>
    <option>Åland Islands</option>
    <option>Albania</option>
    <option>Algeria</option>
    <option>American Samoa</option>
    <option>Andorra</option>
    <option>Angola</option>
    <option>Anguilla</option>
    <option>Antarctica</option>
    ...etc...
  </select>

  <label for="country">or other</label>

</datalist>

<input type="text"
  id="country" name="country"
  size="50"
  list="countrydata"
  autocomplete="off" />

Ver la Pen
HTML5 <datalist> autocomplete fallback
por SitePoint (@SitePoint)
en CodePen.

En navegadores modernos, los elementos <option> se integran en el <datalist> y la etiqueta “or other” no se muestra. Se ve idéntico al ejemplo anterior, pero un valor de formulario countryselect se establecerá en una cadena vacía.

En IE9 y versiones anteriores, tanto los campos de entrada de texto (<select> muy largos) como los campos de texto están activos:

Ambos valores podrían ingresarse en viejos IE. Su aplicación debe decidir si:

  • determinar cuál es más válido, o
  • utilizar una pequeña función JavaScript para restablecer uno cuando se cambie el otro

Usando <datalist> en controles no de texto

Los navegadores basados en Chrome también pueden aplicar valores <datalist> a:

  1. Una entrada con el tipo de "date". El usuario puede elegir de un rango de opciones definidas como valores YYYY-MM-DD pero presentadas en su formato local.

  2. Una entrada con el tipo de "color". El usuario puede elegir de una selección de opciones de color definidas como valores hexadecimales de seis dígitos (los valores de tres dígitos no funcionan).

  3. Una entrada con el tipo de "range". El control deslizante muestra marcas de verificación, aunque esto no limita el valor que se puede ingresar.

Ver el Pen
HTML5 <datalist> en otros tipos de entrada
por SitePoint (@SitePoint)
en CodePen.

<datalist> Estilizado con CSS

Si alguna vez has luchado por estilizar una <select> caja, … ¡lo tuviste fácil!

Un <input> puede estilizarse como normal, pero una <datalist> vinculada y sus elementos secundarios <option> no se pueden estilizar con CSS. El renderizado de la lista está completamente determinado por la plataforma y el navegador.

I hope this situation improves, but for now, a solution is proposed at MDN which:

  1. anula el comportamiento predeterminado del navegador
  2. trata efectivamente la <datalist> como un <div> para que pueda estilizarse con CSS
  3. replica toda la funcionalidad de autocompletar en JavaScript

I’ve enhanced it further and the code is available on GitHub. To use it, load the script anywhere in your HTML page as an ES6 module. The jsDelivr CDN URL can be used:

<script src="https://cdn.jsdelivr.net/npm/datalist-css/dist/datalist-css.min.js"></script>

O puedes instalarlo con npm si estás utilizando un empaquetador:

npm install datalist-css

Tus elementos <datalist> deben usar el formato <option>value</option>. Por ejemplo:

<datalist id="mylist">
  <option>label one</option>
  <option>label two</option>
  <option>label three</option>
</datalist>

Nota: <option value="value" /> no se puede usar, ya que resulta en un elemento vacío que no se puede estilizar!

Luego se puede agregar CSS para estilizar algunos o todos los elementos <datalist> y <option>. Por ejemplo:

datalist {
  position: absolute;
  max-height: 20em;
  border: 0 none;
  overflow-x: hidden;
  overflow-y: auto;
}

datalist option {
  font-size: 0.8em;
  padding: 0.3em 1em;
  background-color: #ccc;
  cursor: pointer;
}

/* Estilo de opción activa */
datalist option:hover, datalist option:focus {
  color: #fff;
  background-color: #036;
  outline: 0 none;
}

Ejemplo:

Ver el Pen
Estilización de autocompletado CSS para HTML5 <datalist>
por SitePoint (@SitePoint)
en CodePen.

El estilo funciona, pero ¿vale la pena el esfuerzo? Sospecho que no…

  • Reimplementar los controles estándar del teclado, ratón y toque del navegador con una accesibilidad razonable es difícil. El ejemplo de MDN no soporta eventos de teclado y, aunque intenté mejorarlo, inevitablemente habrá problemas en algunos dispositivos.
  • Estás confiando en 200 líneas de JavaScript para resolver un problema de CSS. Se minimiza a 1.5kB, pero podría introducir problemas de rendimiento si requiriese muchos elementos <datalist> largos en la misma página.
  • Si JavaScript es un requisito, ¿sería preferible utilizar un componente JavaScript más bonito, consistente y probado en combate?

El control retrocede a un estándar HTML5 <datalist> sin estilo cuando falla JavaScript, pero eso es un beneficio menor.

Creando un <datalist> mejorado con Ajax

Suponiendo que a tu diseñador le parece bien aceptar las diferencias de estilo entre navegadores, es posible mejorar la funcionalidad estándar del <datalist> mediante JavaScript. Por ejemplo:

  1. Implementar validación opcional que solo acepte un valor conocido en el <datalist>.
  2. Establecer elementos <option> a partir de datos devueltos por llamadas Ajax a APIs de búsqueda.
  3. Establecer otros valores de campo cuando se elige una opción. Por ejemplo, al seleccionar “Estados Unidos de América”, se establece “US” en una entrada oculta.

El código principal necesita redefinir elementos <option>, aunque hay varias consideraciones de codificación:

  • Una solicitud de API Ajax solo debería ocurrir después de que se haya ingresado un número mínimo de caracteres.
  • Los eventos de escritura deben ser retrasados. Es decir, una llamada Ajax solo se desencadena una vez que el usuario ha dejado de escribir durante al menos medio segundo.
  • Los resultados de la consulta deben almacenarse en caché para no ser necesario repetir o analizar llamadas idénticas.
  • Las consultas innecesarias deben evitarse. Por ejemplo, al ingresar “un” se obtienen 12 países. No hay necesidad de realizar más llamadas Ajax para “unit” o “united” porque todas las opciones resultantes están contenidas en los primeros 12 resultados.

I’ve created a standard Web Component for this, and the code is available on GitHub. The CodePen example below allows you to select a valid country after entering at least two characters. A music artist autocomplete then returns artists who originated in that country with names matching the search string:

Ver el Pen
HTML5 <datalist> con autocompletado Ajax
por SitePoint (@SitePoint)
en CodePen.

Para utilizarla en tu propia aplicación, carga el script en cualquier parte de tu página HTML como módulo ES6. La URL del CDN jsDelivr puede ser usada:

<script src="https://cdn.jsdelivr.net/npm/datalist-ajax/dist/datalist-ajax.min.js"></script>

O puedes instalarlo con npm si estás usando un empaquetador:

npm install datalist-ajax

Crea un elemento <auto-complete> con un hijo <input> para usar como campo de entrada de datos. Por ejemplo, la búsqueda de países utiliza esto:

<label for="country">country lookup:</label>

<auto-complete
  api="https://restcountries.eu/rest/v2/name/${country}?fields=name;alpha2Code;region"
  resultname="name"
  querymin="2"
  optionmax="50"
  valid="please select a valid country"
>
  <input type="text" id="country" name="country" size="50" required />
</auto-complete>

Atributos del elemento <auto-complete>:

attribute description
api the REST API URL (required)
resultdata the name of the property containing a result array of objects in the returned API JSON (not required if only results are returned)
resultname the name of the property in each result object which matches the search input and is used for datalist <option> elements (required)
querymin the minimum number of characters to enter before a search is triggered (default: 1)
inputdelay the minimum time to wait in milliseconds between keypresses before a search occurs (default debounce: 300)
optionmax the maximum number of autocomplete options to show (default: 20)
valid if set, this error message is shown when an invalid value is selected

La URL REST debe contener al menos un identificador ${id}, que es sustituido por el valor establecido en el <input> con ese id. En el ejemplo anterior, ${country} en la URL api hace referencia al valor en el <input> hijo, que tiene un id de "country". La URL normalmente utilizará la entrada del hijo, pero se pueden referenciar otros campos en la página.

La API restcountries.eu devuelve un objeto único o una matriz de objetos que contienen datos de países. Por ejemplo:

[
  {
    "name": "Cyprus",
    "alpha2Code": "CY",
    "region": "Europe"
  },
  {
    "name": "Sao Tome and Principe",
    "alpha2Code": "ST",
    "region": "Africa"
  },
  {
    "name": "Andorra",
    "alpha2Code": "AD",
    "region": "Europe"
  }
]

El atributo resultdata no necesita ser establecido porque este es el único dato devuelto (no hay objeto envolvente). El atributo resultname debe estar establecido en "name" porque esa propiedad se utiliza para poblar elementos <option> de datalist.

Otros campos pueden ser llenados automáticamente cuando se elige una opción. Las siguientes entradas reciben los datos de las propiedades "alpha2Code" y "region" porque se ha establecido un atributo data-autofill:

<input data-autofill="alpha2Code" type="text" id="countrycode" name="countrycode" readonly />

<input data-autofill="region" type="text" id="region" name="region" readonly />

Cómo funciona datalist-ajax

Puedes omitir esta sección si prefieres no leer 230 líneas de código y mantener la magia intacta!

El código inicialmente crea un nuevo <datalist> dentro del <auto-complete>, al cual adjunta al hijo <input> utilizando un atributo list. Un manejador de eventos input supervisa el <input> y llama a una función runQuery() cuando se han ingresado un número mínimo de caracteres y el usuario ya no está escribiendo.

runQuery() construye la URL de la API a partir de los datos en el formulario y realiza una llamada Ajax utilizando el Fetch API. El JSON devuelto se parsea, luego se construye un fragmento de DOM reutilizable que contiene elementos <option> y se coloca en una caché.

A datalistUpdate() function is called, which updates the <datalist> with the appropriate cached DOM fragment. Further calls to runQuery() avoid Ajax calls if a query has already been cached or a previous query can be used.

A change event handler also monitors the <input>, which is triggered when focus is moved from the field and the value has been modified. The function checks that the value matches a known option and, if necessary, uses the Constraint Validation API to show the error message provided in the valid attribute.

Suponiendo que se ha elegido una opción válida, la función manejadora de cambios llena todos los campos con atributos data-autofill coincidentes. Se mantiene una referencia a los campos de autocompletar para que puedan ser reiniciados si se ingresa una opción inválida posteriormente.

Tenga en cuenta que el DOM en sombra se no utiliza. Esto asegura que el elemento <input> de autocompletar (y el <datalist>) puedan ser estilizados por CSS y accedidos por otros scripts si es necesario.

Dunkin’ <datalist>

El <datalist> HTML5 tiene limitaciones pero es ideal si necesitas un campo de autocompletar simple y agnóstico de framework. La falta de soporte para CSS es una pena, pero los proveedores de navegadores podrían eventualmente abordar ese descuido.

Cualquiera de los códigos y ejemplos mostrados en este tutorial puede ser adoptado para tus propios proyectos.

Preguntas frecuentes sobre los controles de autocompletado ligeros con la lista de datos HTML5

¿Qué es el elemento datalist de HTML5 y cómo funciona?

El elemento datalist de HTML5 es una lista predefinida de opciones para un elemento de entrada. Proporciona una función de “autocompletado” en los elementos de formulario. El elemento datalist utiliza el atributo id para asociarlo con un elemento de entrada específico. El elemento de entrada utiliza el atributo list para identificar el datalist. Dentro del datalist, puedes definir elementos option que representen las opciones disponibles para el campo de entrada.

¿Cómo puedo usar el datalist de HTML5 para autocompletar?

Para usar el datalist de HTML5 para autocompletar, debes asociar el datalist con un campo de entrada. Esto se hace agregando el atributo list al campo de entrada y estableciendo su valor como el id del datalist. El navegador luego sugerirá opciones de autocompletado en función de la entrada del usuario y las opciones definidas en el datalist.

¿Puedo usar el elemento datalist de HTML5 en todos los navegadores?

El elemento datalist de HTML5 es compatible con la mayoría de los navegadores modernos, incluidos Chrome, Firefox, Safari y Edge. Sin embargo, no es compatible con Internet Explorer 9 y versiones anteriores. Puedes verificar la compatibilidad actual del navegador en sitios web como Can I Use.

¿Cómo puedo dar estilo a las opciones del datalist de HTML5?

Desafortunadamente, las opciones de estilo para el elemento datalist de HTML5 son bastante limitadas. La apariencia de la lista desplegable está controlada por el navegador y no se puede personalizar fácilmente con CSS. Sin embargo, puedes estilizar el campo de entrada asociado con el datalist.

¿Puedo usar múltiples datalists para un solo campo de entrada?

No, no puedes asociar múltiples datalists con un solo campo de entrada. El atributo list del campo de entrada solo puede tomar un id, que corresponde a un datalist. Si necesitas proporcionar múltiples conjuntos de opciones, es posible que necesites usar JavaScript para cambiar dinámicamente las opciones en función de la entrada del usuario.

¿Puedo usar el datalist de HTML5 con otros tipos de entrada?

Sí, el datalist de HTML5 puede ser utilizado con varios tipos de entrada, incluyendo texto, búsqueda, url, tel, email, fecha, mes, semana, hora, datetime-local, número, rango y color. Sin embargo, la función de autocompletar podría no funcionar como se espera con algunos tipos de entrada como rango o color.

¿Puedo usar el datalist de HTML5 con un elemento select?

No, el datalist de HTML5 no puede ser utilizado con un elemento select. El datalist está diseñado para proporcionar sugerencias de autocompletar para un campo de entrada, mientras que el elemento select proporciona una lista desplegable de opciones. Si necesitas una lista desplegable, deberías usar el elemento select en su lugar.

¿Puedo usar JavaScript con el datalist de HTML5?

Sí, puedes usar JavaScript con el datalist de HTML5 para agregar, eliminar o cambiar opciones de manera dinámica. Sin embargo, ten en cuenta que el datalist no soporta eventos como onchange o onclick en sus opciones. Necesitas agregar los oyentes de eventos al campo de entrada asociado en su lugar.

¿Puedo usar el datalist de HTML5 para un campo de búsqueda?

Sí, el datalist de HTML5 puede ser una excelente opción para un campo de búsqueda. Puede proporcionar sugerencias de autocompletar en función de la entrada del usuario, lo que puede mejorar la experiencia del usuario. Sin embargo, necesitas poblar manualmente el datalist con los posibles términos de búsqueda.

¿Puedo utilizar la datalista de HTML5 con un textarea?

No, la datalista de HTML5 no se puede usar con un textarea. La datalista está diseñada para proporcionar sugerencias de autocompletar para un campo de entrada, no para un textarea. Si necesitas funcionalidad de autocompletar para un textarea, es posible que debas utilizar una biblioteca de JavaScript o construir tu propia solución.

Source:
https://www.sitepoint.com/html5-datalist-autocomplete/