3.

HTML5 datalist のオートコンプリート実装と限界(input list / Combobox / downshift)

編集
この記事の要点
  • は HTML5 の入力候補リスト。 と組み合わせる
  • 実装が超シンプル: を並べるだけでブラウザ標準のオートコンプリート UIが出る
  • 自由入力も許容(select と違いリストにない値も入る)。完全制限したいなら select を使う
  • 弱点: UI のカスタマイズが効かない(背景色・並び・グルーピング不可)/ 非同期検索が苦手
  • 高機能 UI が必要なら downshift / Headless UI / Combobox など WAI-ARIA Combobox パターンの React ライブラリ

基本: datalist の書き方




  

ユーザがフォーカスすると候補リストが出ます。タイプを始めると部分一致でフィルタされます。optionvalue がそのまま入力欄に入ります。

label と value を分けて表示




  

ブラウザによって label の表示位置が違います(Chrome は右側、Firefox は下)。挙動の統一が難しいので慎重に。

各種 input type との組合せ

type用途備考
text汎用最も一般的
email過去入力メール候補ブラウザの autofill と併存
urlURL 候補
search検索ボックスクリアボタンが付く
colorカラーパレット16進カラーをサジェスト
rangeスライダーの目盛り★ datalist でティック表示
date / time日時候補ブラウザサポート薄め

range のティック




  

動的に候補を生成(JavaScript)

const tags = ['javascript', 'java', 'python', 'php', 'rust', 'go', 'ruby'];

const dl = document.createElement('datalist');
dl.id = 'tag-list';
for (const t of tags) {
  const opt = document.createElement('option');
  opt.value = t;
  dl.appendChild(opt);
}
document.body.appendChild(dl);

document.querySelector('input[name=tag]').setAttribute('list', 'tag-list');

非同期検索(インクリメンタル)

サーバからリアルタイム取得する場合は、入力イベントで datalist を更新します。ただし datalist は内部でさらにブラウザがフィルタするため挙動が複雑になります:

const input = document.querySelector('input[name=q]');
const dl = document.getElementById('q-list');
let timer;

input.addEventListener('input', () => {
  clearTimeout(timer);
  timer = setTimeout(async () => {
    const q = input.value;
    if (!q) return;
    const res = await fetch(`/api/suggest?q=${encodeURIComponent(q)}`);
    const items = await res.json();
    dl.innerHTML = items.map(i => `

select との違い

項目datalistselect
自由入力★ 可能(リスト外も入力可)不可(オプション内のみ)
絞り込みタイプ時に自動フィルタ無し(先頭一致でジャンプのみ)
マルチセレクト不可可(multiple
スタイル不可(ブラウザ固定 UI)限定的に可
option グループ不可可(
必須化required は無入力のみチェックrequired + pattern

リスト外入力を禁止したい

datalist は自由入力を許容する仕様です。「リストの値だけ受け付けたい」場合はJavaScript / pattern で追加検証が必要:

const allowed = ['北海道', '青森県', '岩手県' /* ... */];
const input = document.querySelector('input[name=pref]');

input.addEventListener('change', () => {
  if (!allowed.includes(input.value)) {
    input.setCustomValidity('リストから選択してください');
  } else {
    input.setCustomValidity('');
  }
});

または HTML の pattern 属性で正規表現制限(候補が少ない場合):

アクセシビリティ

  • ブラウザ標準実装なのでキーボード操作とスクリーンリーダー対応は自動。WAI-ARIA Combobox パターンとして読まれる
  • iOS Safari と Android Chrome では実装が貧弱でホイール表示になることがある
  • option 数が多いと(数百以上)遅くなるブラウザがある → 仮想化が無いため
  • label 要素で input と関連付けすることは通常の input と同じく必須

モダンなオートコンプリート ライブラリ

UI を細かく制御したい場合は、WAI-ARIA Combobox を実装した React ライブラリを使うのが定石:

ライブラリ特徴
downshiftヘッドレス(UI 無し)。最大の柔軟性。Render Props / Hooks
@headlessui/react ComboboxTailwind 公式相当。シンプル
react-selectマルチ / 非同期 / グルーピング対応。スタイル制御強い
cmdkVS Code 風コマンドパレット UI
react-aria useComboBoxAdobe 製。アクセシビリティ最強クラス

FAQ

Q: option の並び順は変えられる?
A: 不可。ブラウザは記述順で表示するのみ。アルファベット順にしたければ予めソートして書く。

Q: 候補の最大数は?
A: 仕様上は無制限。実際は数百で遅くなるブラウザあり。多い場合は非同期で動的生成 + 上位 20 件のみ提示する設計に。

Q: option を画像付きにしたい
A: datalist では不可。独自実装 or downshift 系ライブラリを使う。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. meter要素 / meter
  2. progress要素
  3. datalist要素でオートコンプリート候補を表示する
  4. input要素
  5. output要素
  6. keygen要素

最近更新/作成されたページ