入力フォームに自動補完(オートコンプリート)を付けると、ユーザーの入力が速くなり、入力ミスも減ります。この記事では、まずHTML標準の <datalist> で手軽に作り、次にJavaScriptでカスタムUIを実装する方法を解説します。
<input list> + <datalist>(JSほぼ不要)。見た目を自由にしたい・絞り込みやAPI連携が要るときは JavaScriptでカスタム実装します。その際は外側クリックで閉じる処理も入れましょう。キーボード操作やARIA対応まで含む本格実装は検索サジェスト(オートコンプリート)完全ガイドで解説しています。最も簡単:datalist(HTML標準)
<input list="..."> と <datalist> を使うと、JavaScriptなしでブラウザ標準の候補表示が作れます。まずはこれで足りないかを確認しましょう。
↓ 入力欄をクリック/入力すると候補が出ます(動くデモ):
<input list="cities" placeholder="都市名を入力..."> <datalist id="cities"> <option value="東京"></option> <option value="大阪"></option> <option value="名古屋"></option> </datalist>
候補の絞り込みや一致の仕方はブラウザに任せる形です。見た目を自由にしたい・部分一致や独自の並び順にしたい場合は、次のJavaScript実装にします。
JavaScriptでカスタム実装する
入力のたびに候補を絞り込み、自前のリストとして表示します。候補をクリックしたら入力欄に反映してリストを閉じます。入力監視は input イベント、絞り込みは filter で行います。
<input type="text" id="ac-input" placeholder="入力してください..."> <ul id="ac-list"></ul>
const data = ["東京", "大阪", "名古屋", "札幌", "福岡", "横浜", "神戸", "京都"];
const input = document.getElementById("ac-input");
const list = document.getElementById("ac-list");
input.addEventListener("input", () => {
const q = input.value.trim();
list.innerHTML = "";
if (q === "") return;
// 部分一致で絞り込み(前方一致なら startsWith に変える)
const matches = data.filter((item) => item.includes(q));
matches.forEach((match) => {
const li = document.createElement("li");
li.textContent = match; // textContentで安全に
li.addEventListener("click", () => {
input.value = match;
list.innerHTML = ""; // 選んだら閉じる
});
list.appendChild(li);
});
});
値の表示に textContent を使うのはXSS対策です。入力のリアルタイム監視はフォーム入力をリアルタイムで監視する方法も参考になります。
CSSで候補リストを整える
#ac-list {
list-style: none; margin: 4px 0 0; padding: 0;
border: 1px solid #ccc; max-height: 150px; overflow-y: auto;
}
#ac-list li { padding: 8px; cursor: pointer; }
#ac-list li:hover { background: #eee; }
外側をクリックしたら閉じる
候補リストは、入力欄やリスト以外をクリックしたら閉じると自然です。document のクリックを監視して判定します。
document.addEventListener("click", (e) => {
if (e.target !== input && !list.contains(e.target)) {
list.innerHTML = ""; // 外側ならリストを閉じる
}
});
動くデモ:カスタム自動補完を試す
↓ 「と」「大」などを入力すると部分一致で候補が出ます。クリックで選択、入力欄の外をクリックで閉じます(ここまでの実装を1つにまとめたものです):
このデモは filter での絞り込み・クリック選択・外クリックで閉じる、を組み合わせています。キーボード操作(↑↓・Enter)やARIA対応まで加えた完成形は検索サジェスト完全ガイドを参照してください。
サーバーから候補を取得する(debounce + AbortController)
候補が大量にある場合は、サーバーから fetch で取得します。ポイントは2つ。入力のたびにAPIを叩かないよう debounce で間引くこと、前のリクエストを AbortController でキャンセルすることです。
let timer;
let controller;
input.addEventListener("input", () => {
clearTimeout(timer);
timer = setTimeout(async () => { // 300msの入力停止を待つ
const q = input.value.trim();
if (!q) return;
controller?.abort(); // 前のリクエストを中止
controller = new AbortController();
try {
const res = await fetch(`/api/suggest?q=${encodeURIComponent(q)}`,
{ signal: controller.signal });
const items = await res.json();
// items を使って候補リストを描画
} catch (e) {
if (e.name !== "AbortError") console.error(e);
}
}, 300);
});
fetch の基本はfetch APIで非同期通信を行う方法、キーボード操作(↑↓・Enter・Escape)やARIA対応まで含む本格的な実装は検索サジェスト(オートコンプリート)完全ガイドを参照してください。
よくある質問(FAQ)
input イベントで入力値を取得し、候補を filter で絞り込んで<datalist> やカスタムのドロップダウンに表示します。APIから取得する場合は debounce で過度な呼び出しを防ぎます。<datalist> はブラウザ標準の簡易実装で、コードが少なく済みます。JavaScript実装は見た目のカスタマイズ・部分一致・API連携・キーボード操作など自由度が高くなります。まずは <datalist> で足りるか検討しましょう。input に debounce(300ms程度)を設定し、入力が止まったら fetch します。前回のリクエストが終わる前に次が来たら、AbortController でキャンセルして古い結果が表示されないようにします。keydown で ArrowDown / ArrowUp による選択移動、Enter で確定、Escape で閉じる、を実装します。aria-activedescendant などARIA対応を含む完成形は検索サジェスト完全ガイドで解説しています。まとめ
自動補完は、まずHTML標準の <datalist> で手軽に作れます。見た目の調整や部分一致、API連携が必要ならJavaScriptでカスタム実装し、外側クリックで閉じる処理も加えましょう。
サーバー連携では debounce と AbortController が重要です。キーボード操作やARIA対応まで含む本格的な実装は検索サジェスト完全ガイドを参考に、用途に合わせて段階的に作り込んでいきましょう。

