コンテンツにスキップ

コンボボックス

hc-combobox は、入力で絞り込むドロップダウンつきのアクセシブルな 単一選択入力です。 WAI-ARIA 1.2 コンボボックスパターンに 従い、<input>role="combobox" を持ち、ドロップダウンは <ul role="listbox" popover> です。キーボードナビゲーションは aria-activedescendant を使うため、実際の DOM フォーカスは入力に 留まったまま、見えるハイライトだけがユーザーの選択とともに動きます。

hc-menuhc-tooltip と同じアーキテクチャのプリミティブです:

  • 表示 / 非表示と Escape / 外側クリックによる解散は HTML の popover 属性。
  • 入力直下へのリストボックス配置は CSS Anchor Positioning。
  • installCombobox() がフィルタ、キーボード、選択、ARIA の帳簿を 配線。

別名: オートコンプリート、検索付きセレクト。

プリミティブ必要バージョン
HTML popoverChrome 114、Edge 114、Firefox 125、Safari 17
CSS Anchor PositioningChrome 125、Edge 125、Firefox 147、Safari 26

アンカー未対応のブラウザは getBoundingClientRect による配置フックへ フォールバックします。

  • Japan
  • United States
  • United Kingdom
  • France
  • Germany (coming soon)
import { installCombobox } from '@hypermedia-components/core';
installCombobox();

installCombobox() は冪等で、アンインストーラを返します。ゼロ設定の @hypermedia-components/core/behaviors エントリが自動インストールし、 htmx でスワップされた内容も自動で拾います。

  • 入力への ARIA 配線: aria-haspopup="listbox"aria-autocomplete="list"aria-expanded(popover の状態と連動)、 なければ aria-controls、ハイライト中のオプションを追跡する aria-activedescendant
  • 作者が値を与えていなければ、リストボックスに popover="manual"自動設定
  • 入力のインライン anchor-name とリストボックスの position-anchor によるアンカー結合で、ポップオーバーが入力の 直下に着地。
  • フィルタ: 入力のキーストロークごとに、入力文字列を含まない テキストのオプションを隠します(大文字小文字無視)。何も一致しない ときは .hc-combobox__empty<li role="presentation"> が現れ ます。
  • キーボード:
    • は開く / 次の見えるオプションへ移動;
    • は前へ移動;
    • Home / End は最初 / 最後の見える有効なオプションへジャンプ;
    • Enter は選択;
    • Escape は入力値を変えずにリストボックスを閉じる;
    • Tab は閉じて次のタブストップへ譲る。
  • マウス: オプションのクリックで選択。aria-disabled="true" の オプションはスキップされます。
  • 選択: 入力値を埋め、detail{ value, label, option, input } を運ぶバブリングする hc:comboboxselect イベントを発火します。

コンボボックスの入力は本物の <input> です — name を付ければ そのままネイティブにフォーム送信されます:

<div class="hc-combobox">
<input class="hc-combobox__input hc-input" type="text" name="country"
role="combobox" aria-controls="cb-list" aria-label="Country" />
<!-- リストボックスは上の例と同じ -->
</div>

送信されるのは表示テキストです。 選択時に installCombobox() は オプションのラベル(Japan)を入力へ書き込みます — data-value(jp)ではありません。ユーザーは自由入力もできるため、 ワイヤ上の値は常に「見えているものそのまま」です。サーバー側では 通常のテキストフィールドと同じように検証してください。

サーバーがコード値を必要とする場合は、選択イベント(detail{ value, label } を運びます)から hidden 入力へ写してください:

<input type="hidden" name="country" id="country-code">
document.addEventListener('hc:comboboxselect', (e) => {
document.getElementById('country-code').value = e.detail.value ?? '';
});

htmx の往復では同じイベントでリクエストを駆動できます — 次節を 参照してください。

選択は入力上で hc:comboboxselect を発火します。htmx をそのイベントに 配線して、選択をサーバへ送ります。

<input class="hc-combobox__input hc-input"
type="text"
role="combobox"
aria-controls="user-list"
aria-label="Assignee"
data-hx-post="/issues/123/assignee"
data-hx-trigger="hc:comboboxselect"
data-hx-vals='js:{ value: event.detail.value }'>

.hc-comboboxdata-remote を足すと、サーバがフィルタします。 ビヘイビアはクライアントサイドのフィルタをオフにし、htmx リクエストの ライフサイクルから読み込み / 空 / エラーの状態を表出させます:

<div class="hc-combobox" data-remote>
<input class="hc-combobox__input hc-input" type="text" role="combobox"
aria-controls="city-list" aria-label="City"
data-hx-get="/cities" data-hx-trigger="input changed delay:200ms"
data-hx-target="#city-list">
<ul class="hc-combobox__listbox" id="city-list" role="listbox"></ul>
</div>

サーバは一致する <li role="option"> の行だけを返し、htmx がそれを リストボックスへスワップします。リクエストの実行中、ビヘイビアは スピナー行を表示して aria-busy="true" を設定します。空の結果は 「No matches」マーカーを、失敗レスポンスはエラー行を表示します。 3 つのメッセージは i18n カタログ (combobox.loading / combobox.empty / combobox.error)で翻訳 でき、リストボックス単位では data-hc-loading / data-hc-empty / data-hc-error で上書きできます。

デバウンスと実行中キャンセルは htmx に留まります(トリガーの delay:200mshx-sync)— ビヘイビア自身がリクエストすることは 決してありません。

data-allow-create を足すと、ユーザーはリストにない値を選べます。 入力したテキストに完全一致がないとき、合成の 「Create …」 オプションがリストボックスの末尾に現れます。それを選ぶ(クリックまたは Enter)と生のテキストがコミットされ、created: true つきの hc:comboboxselect が発火します。

<div class="hc-combobox" data-allow-create></div>
input.addEventListener('hc:comboboxselect', (e) => {
// e.detail = { value, label, option, input, created }
if (e.detail.created) {
// persist the new value (POST it, add it to the list, …)
}
});

ラベルは i18n カタログで 翻訳できます(combobox.create、例: Create "{value}")。

オプションには任意の HTML を入れられます — アイコン、2 行ラベル、 説明。2 つの任意属性が、フィルタリングと選択をきれいに保ちます:

  • data-label — 選択時に入力へ書き込まれる値(なければオプションの テキスト内容 — リッチマークアップのテキストを含んでしまいます)。
  • data-search — フィルタが照合するテキスト(なければラベル)。 表示されないエイリアス / キーワードに一致させるのに使います。
  • 🇯🇵 Japan Asia
  • 🇫🇷 France Europe
  • 🇧🇷 Brazil South America

フィルタは一致しないオプションを hidden 属性で隠します。リッチ レイアウトのためにオプションへ display(flex/grid)を与えるなら、 非表示を上書きしないよう :not([hidden]) にスコープしてください:

.hc-combobox__option:not([hidden]) { display: grid; … }
  • 入力がユーザーのアンカーです — フォーカスは常にそこに留まるため、 タイプアヘッドとスクリーンリーダーの読み上げが正しく追跡されます。 aria-activedescendant は DOM フォーカスを動かさずにハイライトを 動かします。
  • コンボボックスには常にアクセシブルな名前を与えてください。 <label> で包む、aria-label を設定する、または aria-labelledby を使います。
  • リストボックスは role="listbox" を、各子は role="option" を 持ちます。利用不可の行は disabled ではなく aria-disabled="true" で印を付けてください — <li> はフォーカス 可能なフォームコントロールではないため、disabled は効きません。
  • アクティブなオプションの見えるフォーカスインジケーターは --hc-color-focus-ring を使い、data-color テーマをまたいで同期 します。

MVP は表面を小さく保ちます。次のパターンは先送りです:

  • 複数選択 — 複数の選択値を持つタグ入力。別コンポーネント hc-multicombobox として出荷済みです。
  • 組み込みのデバウンス / 実行中キャンセル — 非同期読み込み自体は サポートされます(リモート(非同期)オプションを 参照)が、リクエストのタイミングはビヘイビアに同梱せず htmx に 留まります(トリガーの delay:hx-sync)。
  • strict モード — 自由テキストを値として受け入れることは data-allow-create でサポートされます。その 逆 — オプションに一致しないとき閉じる際に入力をクリアする — は まだ将来のオプトインフラグです。

component トークン(component.tokens.json):

トークンパス用途
combobox.listbox.bg / fg / border / radiusリストボックスの面。
combobox.listbox.max-heightリストボックスがスクロールし始める上限。
combobox.listbox.padding-block / min-width / offsetリストボックスの間隔とアンカーオフセット。
combobox.option.padding-x / padding-y / font-sizeオプションのレイアウト。
combobox.option.fg / hover-bg / active-bg / selected-bg / selected-fg / disabled-fgオプションの状態。
combobox.empty-fg「No matches」プレースホルダーの色。
生成される CSS 変数を表示
--hc-combobox-listbox-bg | -listbox-fg | -listbox-border | -listbox-radius
--hc-combobox-listbox-max-height | -listbox-padding-block
--hc-combobox-listbox-min-width | -listbox-offset
--hc-combobox-option-padding-x | -option-padding-y | -option-font-size
--hc-combobox-option-fg | -option-hover-bg | -option-active-bg
--hc-combobox-option-selected-bg | -option-selected-fg
--hc-combobox-option-disabled-fg
--hc-combobox-empty-fg
--hc-color-focus-ring (inherited from data-color)
  • セレクト — リストが短く、モバイルでネイティブの OS ピッカーが欲しいとき。
  • メニュー — 項目が値ではなくアクションのとき。
  • インプット — 素のテキスト入力。