Controles de Autocompletar Leve com a Lista de Dados HTML5

Neste tutorial, vamos aprofundar nosso estudo no pouco utilizado elemento HTML5 <datalist>. Ele pode implementar um controle de formulário de autocompletar leve, acessível e compatível com vários navegadores, sem necessitar de JavaScript.

O que há de errado com <select>?

Os controles HTML5 <select> são ideais quando você deseja que o usuário escolha entre um pequeno intervalo de opções. Eles são menos práticos quando:

  • há muitas opções, como países ou cargos
  • o usuário deseja inserir sua própria opção que não está na lista

A solução óbvia é um controle de autocompletar. Isso permite que o usuário insira alguns caracteres, o que limita as opções disponíveis para uma seleção mais rápida.

<select> irá pular para o local certo conforme você começa a digitar, mas isso nem sempre é óbvio. Isso não funcionará em todos os dispositivos (como telas sensíveis ao toque) e reinicia em um segundo ou dois.

Os desenvolvedores muitas vezes recorrem a uma das muitas soluções alimentadas por JavaScript, mas um controle de autocompletar personalizado nem sempre é necessário. O elemento HTML5 <datalist> é leve, acessível e não possui dependências de JavaScript. Você pode ter ouvido dizer que é problemático ou carece de suporte. Isso não é verdade em 2021, mas existem inconsistências e ressalvas nos navegadores.

<datalist> Quick Start

Escolher seu país em uma lista com mais de 200 opções é um candidato ideal para um controle de preenchimento automático. Defina um <datalist> com elementos filhos <option> para cada país diretamente em uma 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>

O id do datalist pode então ser referenciado por um atributo list em qualquer campo <input>:

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

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

Confusamente, é melhor definir autocomplete="off". Isso garante que o usuário veja valores no <datalist> mas não valores que ele anteriormente inseriu no navegador.

O resultado:

Esta é a renderização padrão no Microsoft Edge. Outras aplicações implementam funcionalidade semelhante, mas o visual difere entre plataformas e navegadores.

<option> Opções

Usar a etiqueta como um texto filho de um <option> é comum:

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

Usar um atributo value produz resultados idênticos:

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

Nota: a barra /> de fechamento é opcional no HTML5, embora possa ajudar a prevenir erros de codificação.

Você também pode definir um valor de acordo com uma etiqueta escolhida usando qualquer um dos seguintes formatos.

Opção 1:

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

Opção 2:

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

Em ambos os casos, o campo de entrada é definido como 1, 2 ou 3 quando uma opção válida é escolhida, mas a IU varia entre navegadores:

  • O Chrome exibe uma lista com tanto o valor quanto a etiqueta. Apenas o valor permanece quando uma opção é escolhida.
  • O Firefox exibe uma lista com apenas a etiqueta. Ela muda para o valor quando uma opção é escolhida.
  • O Edge exibe apenas o valor.

O exemplo do CodePen a seguir mostra todas as variações:

Veja a Pen
Exemplos de autocompletar HTML5 <datalist>
por SitePoint (@SitePoint)
no CodePen.

As implementações evoluirão, mas, por enquanto, eu aconselharia a não usar um valor e uma etiqueta, pois é provável que confunda os usuários. (Uma solução alternativa é discutida abaixo.)

<datalist> Suporte e Alternativas nos Navegadores

O elemento <datalist> é bem suportado nos navegadores modernos assim como no Internet Explorer 10 e 11:

Existem várias notas sobre a implementação, mas elas não afetarão a maioria dos usos. O pior que poderia acontecer é que um campo volte a ser uma entrada de texto padrão.

Se você realmente precisa suportar o IE9 e versões anteriores, há um padrão de fallback que usa um <select> padrão em conjunto com uma entrada de texto quando o <datalist> falha. Adaptando o exemplo 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" />

Veja a Pen
HTML5 <datalist> autocomplete fallback
por SitePoint (@SitePoint)
no CodePen.

Em navegadores modernos, os elementos <option> se tornam parte do <datalist> e a etiqueta “or other” não é mostrada. Parece idêntico ao exemplo acima, mas um valor de formulário countryselect será definido como uma string vazia.

No IE9 e versões anteriores, tanto os campos de entrada de texto quanto o <select> (muito longo) estão ativos:

Ambos os valores poderiam ser inseridos em versões antigas do IE. Sua aplicação deve decidir entre:

  • determinar qual é o mais válido, ou
  • usar uma pequena função JavaScript para redefinir um quando o outro é alterado

Usando <datalist> em Controles Não-Texto

Navegadores baseados no Chrome também podem aplicar valores <datalist> a:

  1. Uma entrada com o tipo de "date". O usuário pode escolher de uma gama de opções definidas como valores YYYY-MM-DD mas apresentadas em seu formato local.

  2. Um input com o tipo "color". O usuário pode escolher dentre uma seleção de opções de cores definidas como valores hexadecimais de seis dígitos (valores de três dígitos não funcionam).

  3. Um input com o tipo "range". O controle deslizante mostra marcas de seleção, embora isso não limite qual valor pode ser inserido.

Veja a Pen
HTML5 <datalist> em outros tipos de input
por SitePoint (@SitePoint)
no CodePen.

<datalist> Estilização CSS

Se você já lutou para estilizar uma caixa <select>, … você teve facilidade!

Um <input> pode ser estilizado normalmente, mas um <datalist> vinculado e seus elementos filhos <option> não podem ser estilizados em CSS. O renderizamento da lista é totalmente determinado pela plataforma e navegador.

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

  1. substitui o comportamento padrão do navegador
  2. trata efetivamente o <datalist> como um <div> para que possa ser estilizado em CSS
  3. replica toda a funcionalidade de autocompletar em 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>

Ou você pode instalá-lo com o npm se estiver usando um empacotador:

npm install datalist-css

Seus elementos <datalist> devem usar o formato <option>value</option>. Por exemplo:

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

Nota: <option value="value" /> não pode ser usado, pois resulta em um elemento vazio que não pode ser estilizado!

Em seguida, o CSS pode ser adicionado para estilizar alguns ou todos os elementos <datalist> e <option>. Por exemplo:

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 da opção ativa */
datalist option:hover, datalist option:focus {
  color: #fff;
  background-color: #036;
  outline: 0 none;
}

Exemplo:

Veja a Pen
Estilização CSS do autocomplete do HTML5 <datalist>
por SitePoint (@SitePoint)
no CodePen.

O estilo funciona, mas vale a pena o esforço? Suspeito que não…

  • Reimplementar os controles padrão do teclado, mouse e toque do navegador com acessibilidade razoável é difícil. O exemplo da MDN não suporta eventos de teclado e, embora eu tenha tentado melhorá-lo, inevitavelmente haverá problemas em alguns dispositivos.
  • Você está dependendo de 200 linhas de JavaScript para resolver um problema de CSS. Ele minifica para 1,5kB, mas poderia introduzir problemas de desempenho se você precisasse de muitos elementos <datalist> longos na mesma página.
  • Se o JavaScript for um requisito, seria preferível usar um componente JavaScript mais bonito, consistente e testado em batalhas?

O controle recua para um padrão HTML5 <datalist> sem estilização quando o JavaScript falha, mas isso é um benefício menor.

Criar um <datalist> aprimorado com Ajax

Presumindo que seu designer esteja disposto a aceitar diferenças de estilo entre navegadores, é possível aprimorar a funcionalidade padrão do <datalist> usando JavaScript. Por exemplo:

  1. Implementar validação opcional que aceita apenas um valor conhecido no <datalist>.
  2. Definir elementos <option> a partir de dados retornados por chamadas Ajax a APIs de pesquisa.
  3. Definir outros valores de campo quando uma opção é escolhida. Por exemplo, selecionar “Estados Unidos da América” define “US” em uma entrada oculta.

O código principal precisa redefinir elementos <option>, embora haja várias considerações de codificação:

  • Uma solicitação à API Ajax deve ocorrer apenas após a entrada de um número mínimo de caracteres.
  • Eventos de digitação devem ser debounced. Ou seja, uma chamada Ajax é acionada apenas após o usuário parar de digitar por pelo menos meio segundo.
  • Os resultados da consulta devem ser armazenados em cache para que não seja necessário repetir ou analisar chamadas idênticas.
  • Deve-se evitar consultas desnecessárias. Por exemplo, ao inserir “un” são retornados 12 países. Não há necessidade de fazer mais chamadas Ajax para “unit” ou “united” porque todas as opções resultantes estão contidas nos 12 resultados originais.

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:

Veja a demonstração em
HTML5 <datalist> com autocompletar Ajax
por SitePoint (@SitePoint)
no CodePen.

Para usá-la em sua própria aplicação, carregue o script em qualquer parte de sua página HTML como um módulo ES6. A URL do CDN jsDelivr pode ser usada:

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

Ou você pode instalá-lo com npm se estiver usando um empacotador:

npm install datalist-ajax

Crie um elemento <auto-complete> com um filho <input> para usar como campo de entrada de dados. Por exemplo, a pesquisa de países usa isso:

<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 do 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

A URL REST deve conter pelo menos um identificador ${id}, que é substituído pelo valor definido no <input> com esse id. No exemplo acima, ${country} na URL api refere-se ao valor no <input> filho, que tem um id de "country". A URL normalmente usará o input filho, mas qualquer outro campo na página pode ser referenciado.

A API restcountries.eu retorna um objeto único ou uma matriz de objetos contendo dados do país. Por exemplo:

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

O atributo resultdata não precisa ser definido porque este é o único dado retornado (não há objeto envoltório). O atributo resultname deve ser definido como "name" porque essa propriedade é usada para preencher elementos <option> do datalist.

Outros campos podem ser preenchidos automaticamente quando uma opção é escolhida. Os seguintes inputs recebem os dados das propriedades "alpha2Code" e "region" porque um atributo data-autofill foi definido:

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

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

Como funciona o datalist-ajax

Você pode pular esta seção se preferir não ler 230 linhas de código e manter a magia viva!

O código inicialmente cria um novo <datalist> dentro do <auto-complete>, que é anexado ao filho <input> usando um atributo list. Um manipulador de evento input monitora o <input> e chama a função runQuery() quando um número mínimo de caracteres foi inserido e o usuário não está mais digitando.

runQuery() constrói a URL da API a partir dos dados no formulário e faz uma chamada Ajax usando a API Fetch. O JSON retornado é analisado, então é construído um fragmento de DOM reutilizável contendo elementos <option> e colocado em um cache.

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.

Supondo que uma opção válida tenha sido escolhida, a função de manipulador de mudança preenche todos os campos com atributos data-autofill correspondentes. Uma referência aos campos de preenchimento automático é retida para que possam ser redefinidos se uma opção inválida for inserida posteriormente.

Note que o DOM影子 é não usado. Isso garante que os elementos <input> (e <datalist>) de auto-completo possam ser estilizados por CSS e acessados por outros scripts, se necessário.

Dunkin’ <datalist>

O <datalist> HTML5 tem limitações, mas é ideal se você precisar de um campo de auto-completo simples e independente de framework. A falta de suporte a CSS é uma pena, mas os fornecedores de navegadores podem eventualmente corrigir esse descuido.

Qualquer parte do código e exemplos mostrados neste tutorial pode ser adotada em seus próprios projetos.

Perguntas Frequentes Sobre Controles de Autocompletar Leve com a Lista de Dados do HTML5

O que é o elemento datalist do HTML5 e como funciona?

O elemento datalist do HTML5 é uma lista pré-definida de opções para um elemento de entrada. Ele fornece um recurso de “autocompletar” em elementos de formulário. O elemento datalist usa o atributo id para associá-lo a um elemento de entrada específico. O elemento de entrada usa o atributo list para identificar o datalist. Dentro do datalist, você pode definir elementos option que representam as opções disponíveis para o campo de entrada.

Como posso usar o datalist do HTML5 para autocompletar?

Para usar o datalist do HTML5 para autocompletar, você precisa associar o datalist a um campo de entrada. Isso é feito adicionando o atributo list ao campo de entrada e definindo seu valor como o id do datalist. O navegador sugerirá opções de autocompletar com base na entrada do usuário e nas opções definidas no datalist.

Posso usar o elemento datalist do HTML5 em todos os navegadores?

O elemento datalist do HTML5 é suportado em a maioria dos navegadores modernos, incluindo Chrome, Firefox, Safari e Edge. No entanto, não é suportado no Internet Explorer 9 e em versões anteriores. Você pode verificar a compatibilidade atual do navegador em sites como Can I Use.

Como posso estilizar as opções do datalist do HTML5?

Infelizmente, as opções de estilo para o elemento datalist do HTML5 são bastante limitadas. A aparência da lista suspensa é controlada pelo navegador e não pode ser facilmente personalizada com CSS. No entanto, você pode estilizar o campo de entrada associado ao datalist.

Posso usar múltiplos datalists para um único campo de entrada?

Não, você não pode associar múltiplos datalists a um único campo de entrada. O atributo list do campo de entrada só pode receber um id, que corresponde a um datalist. Se você precisar fornecer múltiplos conjuntos de opções, pode precisar usar JavaScript para alterar dinamicamente as opções baseadas na entrada do usuário.

Posso usar o datalist do HTML5 com outros tipos de entrada?

Sim, o datalist do HTML5 pode ser usado com vários tipos de entrada, incluindo text, search, url, tel, email, date, month, week, time, datetime-local, number, range e color. No entanto, o recurso de autocompletar pode não funcionar como esperado com alguns tipos de entrada como range ou color.

Posso usar o datalist do HTML5 com um elemento select?

Não, o datalist do HTML5 não pode ser usado com um elemento select. O datalist é projetado para fornecer sugestões de autocompletar para um campo de entrada, enquanto o elemento select fornece uma lista suspensa de opções. Se você precisar de uma lista suspensa, deve usar o elemento select em vez disso.

Posso usar JavaScript com o datalist do HTML5?

Sim, você pode usar JavaScript com o datalist do HTML5 para adicionar, remover ou alterar opções dinamicamente. No entanto, tenha em mente que o datalist não suporta eventos como onchange ou onclick em suas opções. Você precisa adicionar os ouvintes de eventos ao campo de entrada associado em vez disso.

Posso usar o datalist do HTML5 para um campo de pesquisa?

Sim, o datalist do HTML5 pode ser uma ótima escolha para um campo de pesquisa. Ele pode fornecer sugestões de autocompletar baseadas na entrada do usuário, o que pode melhorar a experiência do usuário. No entanto, você precisa popular manualmente o datalist com os termos possíveis de pesquisa.

Posso usar o HTML5 datalist com um textarea?

Não, o HTML5 datalist não pode ser usado com um textarea. O datalist é projetado para fornecer sugestões de preenchimento automático para um campo de entrada, não para um textarea. Se você precisar de funcionalidade de preenchimento automático para um textarea, pode ser necessário usar uma biblioteca JavaScript ou criar sua própria solução.

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