HTML5 データリストを使用した軽量なオートコンプリートコントロール

このチュートリアルでは、あまり使用されていないHTML5の<datalist>要素について深く掘り下げます。これは、JavaScriptを必要とせずに軽量でアクセシブルなクロスブラウザのオートコンプリートフォームコントロールを実装できます。

<select>に何が問題か?

HTML5の<select>コントロールは、ユーザーに少数のオプションから選択させたい場合に理想的です。次の場合には実用的ではありません:

  • 国名や役職など、多くのオプションがある場合
  • ユーザーがリストにない独自のオプションを入力したい場合

明らかな解決策はオートコンプリートコントロールです。これにより、ユーザーはいくつかの文字を入力することで、迅速な選択のために利用可能なオプションを制限できます。

<select>はタイプを開始すると正しい場所にジャンプしますが、常に明らかであるとは限りません。タッチスクリーンなどのすべてのデバイスで動作するわけではなく、1秒か2秒でリセットされます。

開発者はしばしば多くのJavaScriptで動作するソリューションの一つに頼ることがありますが、カスタムオートコンプリートコントロールは常に必要ではありません。HTML5の<datalist>要素は軽量でアクセシブルであり、JavaScriptの依存関係がありません。バグがあるとかサポートが不足していると聞いたかもしれませんが、2021年ではそれは真実ではありませんが、ブラウザの不一致や注意点は存在します。

<datalist> クイックスタート

200を超える国を選択するリストから自分の国を選ぶことは、オートコンプリートコントロールの理想的な候補です。HTMLページ内で各国に対して<datalist>を子<option>要素と共に定義します:

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

その後、データリストのid<input>フィールドのlist属性で参照できます:

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

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

混乱を避けるために、autocomplete="off"を設定するのが最善です。これにより、ユーザーは<datalist>内の値を表示されますが、ブラウザで以前に入力した値は表示されません。

結果:

これはMicrosoft Edgeでのデフォルトのレンダリングです。他のアプリケーションも同様の機能を実装していますが、プラットフォームやブラウザによって外観は異なります。

<option> オプション

<option>のテキスト子としてラベルを使用するのは一般的です:

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

value属性を使用すると同じ結果が得られます:

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

注意: HTML5では終了/>スラッシュはオプションですが、コーディングエラーを防ぐのに役立つ場合があります。

選択されたラベルに基づいて値を設定することもできます。以下のフォーマットのいずれかを使用できます。

オプション1:

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

オプション2:

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

いずれの場合も、有効なオプションが選択されると入力フィールドが12、または3に設定されますが、ブラウザによってUIは異なります。

  • Chromeは値とラベルの両方を含むリストを表示します。オプションが選択されると、値のみが残ります。
  • Firefoxはラベルのみを含むリストを表示し、オプションが選択されると値に切り替わります。
  • Edgeは値のみを表示します。

以下のCodePenの例は、すべてのバリエーションを示しています:

See the Pen
HTML5 <datalist> autocomplete examples
by SitePoint (@SitePoint)
on CodePen.

実装は進化するでしょうが、現時点では、値とラベルを使用しないことをお勧めします。ユーザーを混乱させる可能性が高いからです。(以下で対処法について説明します。)

<datalist> ブラウザサポートとフォールバック

<datalist> 要素は、現代のブラウザだけでなく、Internet Explorer 10および11でもよくサポートされています

いくつかの実装上の注意点がありますが、ほとんどの使用には影響しません。最悪の場合、フィールドが標準のテキスト入力に戻るだけです。

もし絶対にIE9以下をサポートしなければならない場合は、<datalist>が失敗した場合に標準の<select>とテキスト入力を組み合わせたフォールバックパターンがあります。国の例を適応させると:

<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" />

以下のペンを見てください:
HTML5 <datalist> オートコンプリートフォールバック
by SitePoint (@SitePoint)
on CodePen.

現代のブラウザでは、<option>要素は<datalist>の一部となり、“その他”ラベルは表示されません。外観は上記の例と同一ですが、countryselectフォーム値は空の文字列に設定されます。

IE9以下では、非常に長い<select>とテキスト入力フィールドの両方がアクティブです:

古いIEでは両方の値を入力できます。アプリケーションは以下のいずれかを行う必要があります:

  • どちらが最も有効かを決定する、または
  • 一方が変更されたときに他方をリセットする小さなJavaScript関数を使用する

<datalist>を非テキストコントロールで使用する

Chromeベースのブラウザでは、<datalist>の値を以下に適用できます:

  1. typeが"date"のinput。ユーザーはYYYY-MM-DD値として定義された範囲のオプションから選択できますが、ロケール形式で表示されます。

  2. 色を選択できる入力欄で、6桁の16進数で定義された色のオプションから選択できます(3桁の値は使用できません)。

  3. スライダーで値を選択できる入力欄で、目盛りが表示されますが、これは入力可能な値を制限しません。

SitePoint (@SitePoint) による CodePen 上のデモ
HTML5 <datalist> を他の入力タイプで使用
をご覧ください。

<datalist> CSS スタイリング

<select> ボックスのスタイル設定に苦労したことがあるなら、…それだけではありません!

<input> は通常通りスタイルを設定できますが、リンクされた <datalist> とその子 <option> 要素は CSS でスタイルを設定できません。リストのレンダリングはプラットフォームとブラウザに完全に依存します。

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

  1. ブラウザのデフォルトの動作を上書き
  2. <datalist><div> のように扱うことで CSS でスタイルを設定できるようになります
  3. 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>

また、バンドラを使用している場合は、npmでインストールすることもできます:

npm install datalist-css

あなたの<datalist>要素は<option>value</option>形式を使用しなければなりません。例えば:

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

注: <option value="value" />は使用できません。これはスタイルを適用できない空の要素になるためです!

CSSを追加して、いくつかまたはすべての<datalist>および<option>要素のスタイルを設定できます。例えば:

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;
}

/* アクティブなオプションのスタイリング */
datalist option:hover, datalist option:focus {
  color: #fff;
  background-color: #036;
  outline: 0 none;
}

例:

SitePoint (@SitePoint)による
HTML5 <datalist> オートコンプリート CSSスタイリング
のペンをCodePenで見ることができます。

スタイリングは機能しますが、それに価値があるでしょうか?私はそうは思いません…

  • ブラウザの標準のキーボード、マウス、タッチコントロールを合理的なアクセシビリティで再実装することは困難です。MDNの例はキーボードイベントをサポートしておらず、改善しようとしましたが、いくつかのデバイスで問題が発生することは避けられません。
  • CSSの問題を解決するために200行のJavaScriptに依存しています。これは1.5kBに最小化されますが、同じページに多くの長い<datalist>要素が必要な場合、パフォーマンスの問題を引き起こす可能性があります。
  • JavaScriptを必要とする場合、よりきれいで一貫性があり、経験済みのJavaScriptコンポーネントを使用する方が望ましいでしょうか?

JavaScriptが失敗した場合、コントロールはスタイリングがない標準のHTML5 <datalist>にフォールバックしますが、それは小さな利点に過ぎません。

Ajaxで強化された<datalist>を作成する

デザイナーがブラウザのスタイリングの違いを受け入れることができると仮定すると、JavaScriptを使用して標準の<datalist>の機能を強化することが可能です。例えば:

  1. オプションの検証を実装し、<datalist>内でのみ既知の値を受け入れる。
  2. Ajax呼び出しによって返されたデータから<option>要素を設定する。
  3. オプションが選択されたときに他のフィールドの値を設定します。例えば、「アメリカ合衆国」を選択すると、非表示の入力に「US」が設定されます。

コードは主に<option>要素を再定義する必要がありますが、いくつかのコーディング上の考慮事項があります:

  • Ajax APIリクエストは、最小限の文字数が入力されるまで発生しないべきです。
  • タイピングイベントはデバウンスされるべきです。つまり、Ajax呼び出しは、ユーザーが少なくとも半秒間タイピングを停止した後にのみトリガーされます。
  • クエリ結果はキャッシュされるべきであり、同じ呼び出しを繰り返すか、同じ呼び出しを解析する必要がないようにする。
  • 不必要なクエリーは避けるべきです。例えば、“un”と入力すると12カ国が返されます。“unit”“united”に対してさらなるAjaxコールを行う必要はありません。なぜなら、それらの結果はすべて元の12の結果に含まれているからです。

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:

デモは
HTML5 <datalist> with Ajax autocomplete
by SitePoint (@SitePoint)
on CodePen.

これを独自のアプリケーションで使用するには、HTMLページの任意の場所にES6モジュールとしてスクリプトを読み込んでください。jsDelivr CDNのURLを使用できます:

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

または、バンドラーを使用している場合はnpmでインストールできます:

npm install datalist-ajax

データ入力フィールドとして使用する子<input>を持つ<auto-complete>要素を作成します。例えば、国名検索はこれを使用します:

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

<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

REST URLには少なくとも1つの${id}識別子が含まれている必要があり、これはidを持つ<input>で設定された値に置き換えられます。上記の例では、api URL内の${country}は、"country"というidを持つ子の<input>の値を参照します。URLは通常、子の入力を使用しますが、ページ上の他のフィールドも参照できます。

restcountries.eu APIは、国データを含む単一のオブジェクトまたはオブジェクトの配列を返します。例えば:

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

resultdata属性は設定する必要はありません。これが返される唯一のデータであり(ラッパーオブジェクトはありません)、resultname属性は"name"に設定される必要があります。このプロパティは、データリスト<option>要素を埋めるために使用されます。

選択したオプションのときに他のフィールドを自動入力できます。次の入力は、data-autofill属性が設定されているため、"alpha2Code"および"region"プロパティのデータを受け取ります:

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

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

datalist-ajaxのしくみ

230行のコードを読みたくない、または魔法を維持したい場合は、このセクションをスキップできます!

コードは最初に<auto-complete>内に新しい<datalist>を作成し、list属性を使用してそれを子の<input>に接続します。<input>inputイベントハンドラは、最小限の文字数が入力され、ユーザーがまだ入力していない場合にrunQuery()関数を呼び出します。

runQuery()はフォーム内のデータからAPI URLを構築し、Fetch APIを使用してAjax呼び出しを行います。返されたJSONが解析され、<option>要素を含む再利用可能なDOMフラグメントが構築され、キャッシュに格納されます。

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.

有効なオプションが選択されたと仮定すると、changeハンドラ関数はdata-autofill属性に一致するすべてのフィールドを埋めます。自動アフィルフィールドへの参照は保持されており、無効なオプションが後で入力された場合にリセットできます。

シャドウDOMは使用されていません。これにより、CSSでスタイルを設定し、必要に応じて他のスクリプトからアクセスできるように、自動補完の<input>(および<datalist>)要素が保証されます。

ダンキン’<datalist>

HTML5<datalist>には制限がありますが、シンプルなフレームワーク非依存の自動補完フィールドが必要な場合に最適です。CSSサポートの欠如は残念ですが、ブラウザベンダーはその見落としについて最終的に対処するかもしれません。

このチュートリアルで示されているコードや例のいずれも、あなた自身のプロジェクトに採用できます。

軽量なオートコンプリートコントロールに関するHTML5 Datalistについてのよくある質問

HTML5のdatalist要素とは何で、どのように機能するのですか?

HTML5のdatalist要素は、input要素の事前定義されたオプションのリストです。これは、フォーム要素に「オートコンプリート」機能を提供します。datalist要素はid属性を使用して特定のinput要素と関連付けられます。input要素はlist属性を使用してdatalistを識別します。datalist内では、inputフィールドの利用可能なオプションを表すoption要素を定義できます。

HTML5のdatalistをオートコンプリートにどのように使用できますか?

HTML5のdatalistをオートコンプリートに使用するには、datalistをinputフィールドに関連付ける必要があります。これは、inputフィールドにlist属性を追加し、その値をdatalistのidに設定することで行われます。ブラウザーは、ユーザーの入力とdatalist内で定義されたオプションに基づいてオートコンプリートオプションを提案します。

HTML5のdatalist要素をすべてのブラウザーで使用できますか?

HTML5のdatalist要素は、Chrome、Firefox、Safari、Edgeなどのほとんどの最新のブラウザーでサポートされています。ただし、Internet Explorer 9以前のバージョンではサポートされていません。現在のブラウザー互換性を「Can I Use」などのウェブサイトで確認できます。

HTML5のdatalistオプションをどのようにスタイル設定できますか?

残念ながら、HTML5のdatalist要素のスタイリングオプションはかなり限られています。ドロップダウンリストの外観はブラウザーによって制御され、CSSで簡単にカスタマイズできません。ただし、datalistに関連付けられたinputフィールドをスタイル設定できます。

1つのinputフィールドに複数のdatalistsを使用できますか?

いいえ、複数のデータリストを単一の入力フィールドに関連付けることはできません。入力フィールドのlist属性は、1つのidしか取ることができず、それは1つのデータリストに対応します。複数のオプションセットを提供する必要がある場合は、JavaScriptを使用して、ユーザー入力に基づいてオプションを動的に変更する必要があります。

HTML5のデータリストは他の入力タイプと一緒に使えますか?

はい、HTML5のデータリストは、テキスト、検索、URL、電話、メール、日付、月、週、時間、datetime-local、数値、範囲、および色など、さまざまな入力タイプで使用できます。ただし、範囲や色などの一部の入力タイプでは、自動補完機能が期待どおりに機能しない場合があります。

HTML5のデータリストはselect要素と一緒に使えますか?

いいえ、HTML5のデータリストはselect要素と一緒に使うことはできません。データリストは、入力フィールドの自動補完提案を提供するために設計されており、select要素はオプションのドロップダウンリストを提供します。ドロップダウンリストが必要な場合は、select要素を使用するべきです。

HTML5のデータリストでJavaScriptを使えますか?

はい、JavaScriptを使用して、オプションを動的に追加、削除、または変更することができます。ただし、データリストのオプションでonchangeやonclickなどのイベントをサポートしていないことに注意してください。イベントリスナーを関連付けられた入力フィールドに追加する必要があります。

HTML5のデータリストは検索フィールドに使えますか?

はい、HTML5のデータリストは検索フィールドに適しています。ユーザーの入力に基づいて自動補完提案を提供できるため、ユーザーエクスペリエンスを向上させることができます。ただし、可能な検索用語でデータリストを手動で設定する必要があります。

HTML5のdatalistをtextareaと共に使用できますか?

いいえ、HTML5のdatalistはtextareaと共に使用することはできません。datalistは入力フィールドに対してオートコンプリートの提案を提供するために設計されており、textareaには適用されません。textareaにオートコンプリート機能が必要な場合、JavaScriptライブラリを使用するか、独自のソリューションを構築する必要があります。

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