オートコンプリート検索は、ユーザーの入力に応じて検索候補をリアルタイムで表示する機能です。
ユーザーは候補から目的の項目を選択することで、素早く検索を完了できます。
しかし、オートコンプリート検索の実装は簡単にという訳にはいきません。
JavaScriptを使った複雑な処理が必要になることが多く、実装コストが高くなりがちです。
htmxを使えば、シンプルなHTMLの属性だけで、高速で使いやすいオートコンプリート検索を実現できます。
本記事では、htmxとPHPを組み合わせて、最小限のコードでオートコンプリート検索を実装する方法を解説します。
本記事の内容
- オートコンプリート検索のHTML構造
- サジェスト候補の動的取得
- ユーザビリティの向上
- パフォーマンスの最適化
- アクセシビリティの考慮
- サンプルコード
- まとめ
それでは、順を追って説明していきます。
オートコンプリート検索のHTML構造
htmxについてよくわからない場合は、次の記事からご覧ください。
オートコンプリート検索のHTML構造は以下のようになります。
<form> <label for="search">検索:</label> <input type="text" id="search" name="search" hx-post="search.php" hx-trigger="keyup" hx-target="#search-results" hx-indicator=".htmx-indicator"> <div class="htmx-indicator">Searching...</div> <div id="search-results"></div> </form>
hx-post属性で、入力内容をサーバーに送信するURLを指定します。
hx-trigger属性を”keyup”にすることで、キー入力のたびにリクエストが送信されます。
hx-target属性で、サーバーからの応答を表示する要素を指定します。
hx-indicator属性で、リクエストの送信中に表示する要素を指定します。
サジェスト候補の動的取得
PHPを使って、ユーザーの入力に応じた検索候補を動的に生成します。
search.php
<?php
$searchTerm = $_POST['search'];
$suggestions = searchDatabase($searchTerm);
foreach ($suggestions as $suggestion) {
echo "<div class='search-suggestion'>{$suggestion}</div>";
}
?>
ここでは、searchDatabase関数を使って、データベースから検索候補を取得しているものとします。
取得した候補をループ処理し、各候補を要素として出力します。
htmxは、サーバーからの応答を自動的に#search-results要素に挿入します。
ユーザビリティの向上
ユーザーの入力に応じて、検索候補をハイライトするためのCSSを追加します。
.search-suggestion {
padding: 5px;
cursor: pointer;
}
.search-suggestion:hover,
.search-suggestion.focus {
background-color: #f0f0f0;
}
.search-suggestion b {
font-weight: bold;
}
PHPで候補をハイライトするコードを追加します。
<?php
foreach ($suggestions as $suggestion) {
$suggestion = preg_replace("/($searchTerm)/i", "<b>$1</b>", $suggestion);
echo "<div class='search-suggestion'>{$suggestion}</div>";
}
?>
preg_replace関数を使って、ユーザーの入力部分を<b>タグで囲むことで、候補をハイライトします。
パフォーマンスの最適化
オートコンプリート検索では、ユーザーの入力のたびにリクエストが送信されるため、パフォーマンスが重要になります。
以下のような点に注意して、パフォーマンスを最適化しましょう。
- 検索候補の取得は、高速な検索アルゴリズムを使用する(例: インデックスを使った部分一致検索)
- 検索候補の数を制限し、応答サイズを小さくする
- レスポンスをキャッシュし、同じ検索ワードに対しては、キャッシュを返すようにする
アクセシビリティの考慮
オートコンプリート検索をアクセシブルにするために、以下の点に注意します。
- <label>要素を使って、検索入力欄とラベルを関連付ける
- role=”listbox”とrole=”option”を使って、検索候補のセマンティクスを明示する
- 選択中の候補にはaria-selected=”true”を設定する
サンプルコード
以上の内容を組み合わせた完全なサンプルコードは以下の通りです。
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>オートコンプリート検索</title>
<script src="https://unpkg.com/htmx.org@1.7.0"></script>
<style>
.search-suggestion {
padding: 5px;
cursor: pointer;
}
.search-suggestion:hover {
background-color: #f0f0f0;
}
.search-suggestion b {
font-weight: bold;
}
.htmx-indicator {
display: none;
}
.htmx-request .htmx-indicator {
display: inline;
}
</style>
</head>
<body>
<form>
<label for="search">検索:</label>
<input type="text" id="search" name="search" hx-post="search.php" hx-trigger="keyup changed delay:500ms" hx-target="#search-results" hx-indicator=".htmx-indicator">
<div class="htmx-indicator">Searching...</div>
<div id="search-results"></div>
</form>
</body>
</html>
search.php
<?php
function searchDatabase($searchTerm) {
$suggestions = [];
// CSVファイルを開く(本来はデータベースを使うべきだが、ここではCSVで代用している)
if (($handle = fopen("suggestions.csv", "r")) !== false) {
// 一行ずつ読み込む
while (($data = fgetcsv($handle, 1000, ",")) !== false) {
// 検索語を含む行のみ結果に追加
if (stripos($data[0], $searchTerm) !== false) {
$suggestions[] = $data[0];
}
}
fclose($handle);
}
return $suggestions;
}
$searchTerm = $_POST['search'];
$suggestions = searchDatabase($searchTerm);
foreach ($suggestions as $suggestion) {
$suggestion = preg_replace("/($searchTerm)/i", "<b>$1</b>", $suggestion);
echo "<div class='search-suggestion'>{$suggestion}</div>";
}
?>
ちなみに、suggestions.csvは次のようなデータになります。

適当に用意したCSVです。
以下からダウンロード可能です。



