L'autocompletamento è un pattern di design con cui ormai tutti gli utenti del web hanno una certa familiarità. Quando si fa una ricerca, il motore di ricerca suggerisce automaticamente i termini. Quando si compone un nuovo messaggio di e-mail, il programma suggerisce automaticamente i destinatari. Gli sviluppatori web, tuttavia, per implementare questa funzionalità, hanno finora dovuto fare ricorso a discrete quantità di codice Javascript. Uno dei nuovi elementi HTML5, <datalist>
, rende invece nativa sul web la funzionalità dell'autocompletamento.
In questo articolo spiegherò cosa sono le datalist, quando è appropriato usarle, le loro limitazioni e cosa fare per i browser che non le supportano. Iniziamo.
Creare datalist
Per verificare come funzionano le datalist, iniziamo con un tipico input di testo:
<label for="favorite_team">Favorite Team:</label>
<input type="text" name="team" id="favorite_team">
Il campo consente all'utente di inserire il nome della sua squadra del cuore. Di default, all'utente non saranno dati aiuti aggiuntivi per compilare il campo. Ma usando una datalist, possiamo fornire una lista di opzioni che l'utente stesso potrà selezionare per completare il campo. Per fare ciò, definiamo innanzitutto una datalist con un elemento di opzione (<option>
) per ciascun suggerimento:
<datalist>
<option>Detroit Lions</option>
<option>Detroit Pistons</option>
<option>Detroit Red Wings</option>
<option>Detroit Tigers</option>
<!-- etc... -->
</datalist>
Per collegare una datalist ad un campo di input, assegniamo a quest'ultimo un attributo list
. Il valore di questo attributo list
dovrà corrispondere al valore dell'id
che assegneremo alla datalist. Ecco un esempio:
<label for="favorite_team">Favorite Team:</label>
<input type="text" name="team" id="favorite_team" list="team_list">
<datalist id="team_list">
<option>Detroit Lions</option>
<option>Detroit Pistons</option>
<option>Detroit Red Wings</option>
<option>Detroit Tigers</option>
<!-- etc... -->
</datalist>
Notate che l'attributo list
del campo di testo e l'attributo id
della datalist contengono lo stesso valore, team_list
. Ciò crea il collegamento tra i due elementi.
Basta questo. Non c'è bisogno di Javascript per far funzionare una datalist. In figura 1 possiamo vedere cosa vedrà un utente nel suo browser dopo aver inserito la lettera 'D' nel campo di testo.
Nota: Internet Explorer 10 e Opera 12 non richiedono che l'utente digiti un carattere prima di visualizzare il suggerimento, mentre Chrome e Firefox lo richiedono.
Gli elementi <option>
possono avere anche un attributo value
. Ciò è utile quando un utente potrebbe non conoscere il codice associato ad una specifica opzione. Consideriamo questo campo di input per la selezione di uno degli stati USA:
<label for="state">State:</label>
<input type="text" name="state" id="state" list="state_list">
<datalist id="state_list">
<option value="AL">Alabama</option>
<option value="AK">Alaska</option>
<option value="AZ">Arizona</option>
<option value="AR">Arkansas</option>
<!-- etc -->
</datalist>
In questo caso, l'utente vedrà una lista con il nome completo degli stati, ma quando seleziona una voce dalla lista, il campo di testo sarà riempito con il codice dello stato invece che con il nome per esteso. Ecco un esempio:
L'attributo autocomplete
Se l'aspetto delle datalist in figura 1 e figura 2 vi è familiare, è perché i browser hanno implementato da tempo un meccanismo di autocompletamento. Tutti i browser offrono un meccanismo di qualche tipo per il salvataggio e il recupero dei dati immessi dall'utente, dati su cui si basa la funzionalità di autocompletamento.
Gli sviluppatori possono usare l'attributo autocomplete
sui campi di un modulo per istruire il browser sul fatto di tentare o meno di completare automaticamente i dati inseriti dall'utente. I valori possibili sono mostrati nel seguente snippet di codice:
<form>
<!--
Se l'attributo automplete non è specificato, il campo
eredita il valore dell'elemento form che è suo parente.
Se non specificato, il valore di default per l'attributo
autocomplete del form è impostato su "on". Dal momento
che né il campo di input che segue né il form hanno
un attributo autocomplete definito, sarà usato il valore "on".
-->
<input type="text" name="firstName">
<!--
Il valore "on" indica che il browser può salvare
e ricordare il valore immesso per il futuro, e che può
fornire suggerimenti per il completamento.
-->
<input type="text" name="address" autocomplete="on">
<!--
Il valore "off" dice al browser di non salvare il valore
immesso per il campo e di non offrire suggerimenti per il
completamento basati sui valori predentemente inseriti.
Questa via andrebbe seguita se i dati sono particolarmente sensibili
o se il valore non verrà più riusato.
-->
<input type="text" name="secret" autocomplete="off">
</form>
Qual è, dunque, la differenza tra l'attributo autocomplete
e le datalist? L'attributo autocomplete
dice al browser se fornire all'utente opzioni per il completamento basate su quanto l'utente stesso ha precedentemente immesso in un campo e se salvare il valore immesso per il futuro. Le datalist sono invece liste di suggerimenti preparate e fornite dallo sviluppatore che vengono sempre visualizzate, a prescindere da precedenti immissioni di dati.
Attenzione ad un punto. Impostare l'attributo autocomplete
su off
impedisce la visualizzazione delle datalist su Opera. Ecco un esempio:
<!--
Questa datalist non verrà mostrata su Opera perché l'attributo
autocomplete è impostato con il valore "off". Verrà invece mostrata
su tutti gli altri browser.
-->
<input type="text" list="pets" autocomplete="off">
<datalist id="pets">
<option>Cat</option>
<option>Dog</option>
<option>Hamster</option>
<option>Turtle</option>
</datalist>
Altri tipi di input
Mentre l'autocompletamento è tradizionalmente associato ai campi di testo, le datalist possono essere usate anche su alcuni dei nuovi tipi di input definiti in HTML5. Consideriamo l'input di tipo range
, che consente di la creazione di un elemento di form di tipo slider per la selezione di valori. Combinando un input di questo tipo con una datalist, è possibile suggerire all'utente i punti definiti in un certo range.
Per esempio, il seguente input chiede all'utente di fornire un valore tra $5 e $200 per una donazione:
<label for="donation">Donation Amount (USD):</label>
<input type="range" name="donation" id="donation" list="donation_list"
step="5" min="5" max="200">
<datalist id="donation_list">
<option>25</option>
<option>50</option>
<option>100</option>
<option>200</option>
</datalist>
Le immagini che seguono mostrano la visualizzazione dell'input di tipo range
, rispettivamente, su Chrome 24 e Internet Explorer 10.
Come si vede, ogni browser mostra un sottile marcatore per ciascuna opzione definita nella datalist. Inoltre, Chrome aggancia lo slider a questi valori predefiniti quando l'utente sposta lo stesso slider vicino ad essi.
Purtroppo, al momento, Internet Explorer e Chrome sono gli unici browser che supportano le datalist sugli input di tipo range
. La figura 5 mostra il supporto delle datalist sui più comuni tipi di input nei browser moderni.
Quando usare le datalist
Dal momento che le datalist non offrono un meccanismo automatico per richiedere all'utente di selezionare un'opzione definita, esse sono particolarmente adatte per quegli input che possono accettare un qualunque valore.
Di conseguenza, l'esempio degli stati americani non si presta all'uso delle datalist perché c'è un set limitato di valori validi che l'utente deve fornire. Per casi simili, meglio affidarsi ad un menu a tendina (select) perché esso costringe a operare una selezione.
Un'eccezione può essere rappresentata da input con con un numero ampio di opzioni valide. Per esempio, consideriamo un tipico menu tendina per la selezione di una nazione come quello mostrato in figura 6.
Questa lista è problematica per l'utente perché lo costringe a cercare tra centinaia di opzioni per trovare quella giusta. Una funzionalità di autocompletamento è in questo scenario adatta perché l'utente può rapidamente filtrare la lista immettendo uno o due caratteri nel campo.
Ecco come la selezione di una nazione può essere implementata attraverso l'uso di una datalist:
<label for="country">Country:</label>
<input type="text" id="country" list="country_list">
<datalist id="country_list">
<option value="AF">Afghanistan</option>
<option value="AX">Åland Islands</option>
<option value="AL">Albania</option>
<option value="DZ">Algeria</option>
<!-- more -->
</datalist>
La figura qui sotto mostra cosa appare quando l'utente digita il carattere 'U':
Forzare l'immissione di un valore
Mentre le datalist non consentono nativamente di richiedere che un'opzione venga selezionata, possiamo facilmente aggiungere un meccanismo di validazione che possa fare una cosa del genere. Per esempio, il codice che presentiamo qui sotto utilizza le API per la validazione di HTML5 per aggiungere questa funzionalità:
// Trova tutti gli input nel DOM che sono collegati
// a una datalist attraverso l'attributo list
var inputs = document.querySelectorAll('input[list]');
for (var i = 0; i < inputs.length; i++) {
// Quando il valore del campo cambia...
inputs[i].addEventListener('change', function() {
var optionFound = false,
datalist = this.list;
// Determina se esiste un'opzione con il valore corrente del campo di input.
for (var j = 0; j < datalist.options.length; j++) {
if (this.value == datalist.options[j].value) {
optionFound = true;
break;
}
}
// Usa la funzione setCustomValidity della API di validazione HTML5
// per fornire un feedback all'utente nel caso in cui un valore
// non esista nella datalist
if (optionFound) {
this.setCustomValidity('');
} else {
this.setCustomValidity('Please select a valid value.');
}
});
}
L'API per la validazione è implementata su tutti i browser che supportano le datalist. Dunque, se le datalist funzionano, la validazione dovrebbe pure funzionare. Ora, quando l'utente prova a inviare un form con un input che abbia una datalist associata e non ha selezionato un'opzione, vedrà il messaggio di errore visibile nella figura 8.
Figura 8 - Messaggio di errore della API di validazione (Internet Explorer 10)
È importante notare che la API per la validazione dei form di HTML5 non elimina la necessità di una validazione lato server. Gli utenti che usano browser più vecchi non avranno a disposizione questa API di validazione lato client fornita da HTML5, e gli utenti più smaliziati potranno anche sovvertire la struttura degli script.
Insomma, questo approccio, pur funzionando nei browser moderni, presenta serissimi problemi a livello di usabilità per quanti usano browser più vecchi che non supportano questi meccanismi. A questi utenti viene detto che devono selezionare un valore valido, ma se il loro browser non supporta le datalist, essi non potranno vedere le opzioni. Dunque, se pensate di seguire questo approccio, assicuratevi che l'interfaccia funzioni su tutti i browser. Ciò può essere ottenuto prima verificando se il browser supporta le datalist e quindi offrendo un meccanismo alternativo sotto forma di polyfill.
Browser che non supportano le datalist
Nel momento in cui scriviamo questo articolo, le datalist associate ai campi di testo sono supportate da Internet Explorer 10, Firefox 4+, Chrome 20+ e Opera. Uno scenario che lascia purtroppo fuori un grande numero di utenti.
Diversamente da altre nuove funzionalità di HTML5, nella maggior parte dei casi, non c'è bisogno di un lavoro extra nei browser che non supportano le datalist. Di default, la lista di opzioni che viene definita è fatta da meri suggerimenti; pertanto, gli utenti che navigano con browser che non supportano le datalist si limiteranno a compilare il campo di testo senza fruire di alcun suggerimento.
Tuttavia, possono essere fornite delle opzioni di fallback per offrire un'esperienza piena a chi usa browser privi di supporto.
Offrire un contenuto HTML alternativo
Un'opzione, resa popolare da Jeremy Keith, consiste nello sfruttare il fatto che i browser che non supportano le datalist mostreranno comunque gli elementi figli all'utente. Ecco come la datalist per la selezione della nazione potrebbe essere modificata per fornire un'alternativa sotto forma di menu a tendina (select):
<label for="country">Country:</label>
<datalist id="country_list">
<select name="country">
<option value="AF">Afghanistan</option>
<option value="AX">Åland Islands</option>
<option value="AL">Albania</option>
<option value="DZ">Algeria</option>
<option value="AS">American Samoa</option>
<!-- more -->
</select>
If other, please specify:
</datalist>
<input type="text" name=”country” id=”country” list="country_list">
Per gli utenti che usano browser con supporto delle datalist l'interfaccia non cambierà, ma gli utenti che lavorano con browser senza supporto vedranno ora un menu a tendina (select) con le opzioni relative alle nazioni e un campo di testo che potranno usare per inserire un qualunque valore. Il risultato è visibile qui sotto:
Usare un polyfill
Una funzionalità che l'alternativa basata sul menu a tendina non offre è il meccanismo di autocompletamento che le datalist presentano nativamente. Se questo è importante per la datalist che si prevede di usare, una seconda alternativa è quella di usare un polyfill che emuli il comportamento delle datalist.
Per iniziare, bisogna prima determinare se il browser dell'utente supporta le datalist. La popolare libreria per la feature detection Modernizr fornisce un sistema per svolgere la verifica, come possiamo vedere qui di seguito:
if (Modernizr.input.list) {
//Il browser supporta l'attributo 'list' e le datalist.
} else {
//Il browser non supporta né l'attributo 'list' né le datalist.
}
}
Usando questo approccio, possiamo ora sfruttare un polyfill per emulare le datalist per gli utenti con browser che non supportano le datalist. Ci sono molti polyfill disponibili, ma io preferisco usare il widget per l'autocompletamento di jQuery UI. Il codice che segue mostra l'implementazione del polyfill:
var datalist,
listAttribute,
options = [];
// Se il browser non supporta l'attributo 'list'...
if (!Modernizr.input.list) {
// Per ogni campo di testo con un attributo 'list'...
$('input[type="text"][list]').each(function() {
// Trova l'id della datalist
// Usando 'this', trova la datalist che è associata all'input
listAttribute = $(this).attr('list');
datalist = $('#' + listAttribute);
// Se il campo di testo ha una datalist associata
if (datalist.length > 0) {
options = [];
// Crea la lista di opzioni da passare al widget per l'autocompletamento.
datalist.find('option').each(function() {
options.push({ label: this.innerHTML, value: this.value });
});
// Trasforma l'input in un widget jQuery UI.
$(this).autocomplete({ source: options });
}
});
// Rimuove tutte le datalist dal DOM.
$('datalist').remove();
}
La figura qui sotto mostra l'esempio della lista con le nazioni su Safari con il widget di autocompletamento di jQuery UI:
Come avete forse notato, di default il widget per l'autocompletamento di jQuery UI effettua il matching dei caratteri in qualunque posizione del testo, mentre le datalist lo fanno solo all'inizio della stringa di testo. Diversamente dalle datalist native, il widget di jQuery UI può essere modificato per fare il matching in qualsiasi posizione.
Il codice che segue mostra come potete creare una funzionalità di autocompletamento che faccia il matching solo all'inizio della stringa:
<input type="text" id="autocomplete">
<script>
var options = ['Badger', 'Bat', 'Cat', 'Cheetah', 'Crocodile', 'Deer', 'Donkey',
'Elephant', 'Fish', 'Frog', 'Giraffe', 'Gorilla'];
$('#autocomplete').autocomplete({
source: function (req, responseFn) {
var term = $.ui.autocomplete.escapeRegex(req.term),
matcher = new RegExp('^' + term, 'i'),
matches = $.grep(options, function (item) {
return matcher.test(item);
});
responseFn(matches);
}
});
</script>
Versioni più vecchie di Internet Explorer
Affinché un qualunque polyfill per le datalist funzioni sulle versioni più vecchie di Internet Explorer, sono necessari due step aggiuntivi.
Gli elementi option
Il primo: Internet Explorer 9 e precedenti richiedono tutti che gli elementi option
siano figli di elementi select
. Se non lo sono, non saranno riconosciuti, e non saranno visibili al polyfill.
Per fortuna, è qualcosa che è facile da superare. Usando i commenti condizionali, possiamo inserire un elemento select
intorno alle opzioni solo per quelle versioni di Internet Explorer. Ecco l'esempio:
<datalist>
<!--[if IE]><select><!--<![endif]-->
<option>Apple</option>
<option>Banana</option>
<option>Cherry</option>
<!- etc -->
<!--[if IE]><select><!--<![endif]-->
</datalist>
Internet Explorer 9 e versioni precedenti identificheranno ora correttamente le opzioni. Internet Explorer 10 non sarà toccato da questo trucchetto perché i commenti condizionali sono stati eliminati dal parser di questo browser. Ovviamente, tutti gli altri browser diversi da IE ignoreranno i commenti condizionali.
HTML5 Shiv
Su Internet Explorer 8 e versioni precedenti, gli elementi HTML non riconosciuti non possono contenere elementi figli. Pertanto, anche se le opzioni della datalist sono racchiuse all'interno di una select, essi non saranno riconosciuti.
Anche in questo caso c'è per fortuna una soluzione molto semplice. La popolare libreria HTML5 Shiv consente agli elementi sconosciuti per Internet Explorer 6-8 di avere elementi figli. La libreria è compresa in Modernizr; assucuratevi soltanto che il checkbox "html5 shiv" sia selezionato quando configurate il vostro download della libreria.
Limitazioni delle datalist
Sebbene le datalist siano perfette per aggiungere suggerimenti automatici ai campi di testo, esse hanno il difetto di non essere personalizzabili come molte moderne applicazioni web richiedono. Per esempio, non è possibile fare queste cose con una datalist:
- usare i CSS per modificare le sue opzioni di visualizzazione;
- controllare il posizionamento della lista;
- controllare il numero di caratteri digitati prima che il browser mostri i risultati all'utente;
- controllare e fissare cosa è una corrispondenza e cosa no (sensibilità maiuscolo/minuscolo, corrispondenza all'inizio vs. in qualunque posizione, etc.);
- collegare l'input a una fonte di dati lato server.
Ciò significa che se si ha bisogno di una qualunque di queste funzionalità, si dovrà ricorrere ad una soluzione per l'autocompletamento più robusta. Il widget per l'autocompletamento di jQuery UI concede la possibilità di fare tutte le cose prima elencate e anche di più. Tra l'altro, supporta anche Internet Explorer fino alla versione 7 senza bisogno di polyfill. Per maggiori informazioni su questo widget, potete consultare le demo e la documentazione delle API (il widget gestisce solo i campi di testo, pertanto non sarà utile per altri tipi di input come quelli di tipo range
o color
).
Conclusioni
Le datalist costituiscono un modo rapido e nativo per mostrare suggerimenti all'utente. Dal momento che le opzioni sono meri suggerimenti, per tante situazioni non sarà necessario fornire un'alternativa per i browser senza supporto; gli utenti di questi browser non vedranno i suggerimenti. Tutto qui.
Per situazioni in cui si voglia fornire una datalist funzionale a tutti gli utenti, possiamo verificare il supporto della funzionalità e offrire un'alternativa basata su un polyfill.
Se le datalist sono eccellenti per presentare suggerimenti, sono limitate nelle funzionalità che offrono. Se avete bisogno di una soluzione di autocompletamento più robusta, il widget di jQuery UI è un buon punto di partenza.
Nota sull'autore
TJ VanToll è uno sviluppatore web e membro del team di sviluppo di jQuery. Vive a Lansing, Michigan, e scrive sulle sue esperienze con jQuery, HTML5, CSS e altri argomenti sul suo blog. È padre orgoglioso di due figli, e quando non è su internet, è di solito impegnato a inseguirli per casa. Potete trovare TJ sul suo blog o su Twitter .