オートコンプリート検索は、ユーザーの入力に応じて検索候補をリアルタイムで表示する機能です。
ユーザーは候補から目的の項目を選択することで、素早く検索を完了できます。
しかし、オートコンプリート検索の実装は簡単にという訳にはいきません。
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です。
以下からダウンロード可能です。