最小限のコードでオートコンプリート検索を実装 – htmx活用テクニック

最小限のコードでオートコンプリート検索を実装 - htmx活用テクニック プログラミング

オートコンプリート検索は、ユーザーの入力に応じて検索候補をリアルタイムで表示する機能です。
ユーザーは候補から目的の項目を選択することで、素早く検索を完了できます。

しかし、オートコンプリート検索の実装は簡単にという訳にはいきません。
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です。
以下からダウンロード可能です。

オートコンプリート検索用CSV|ジコログ
suggestions.csv 824 Bytes ファイルダウンロードについて ダウンロード
タイトルとURLをコピーしました