kaze風
Combobox
入力しながら候補を絞り込んで選ぶフォーム部品(WAI-ARIA の combobox + listbox)。既定の絞り込みはひらがな・カタカナ・全角半角・大文字小文字を区別せず、IME 変換中の Enter や矢印キーは無視します。選択肢が少なく絞り込みが不要なら Select を使います。
プレビュー
「とうきょう」「オオサカ」でも絞り込めます
使いどころ
使う場面
- 選択肢が 10 件を超えるとき、または名前の一部で探したいとき(取引先、担当者、国、地名)
- ふりがなや別名で探せるようにしたいとき。keywords にヨミや略称を持たせる
- 名前(label)ではなく ID(value)をフォームで送りたいとき。name を付けると hidden で value が送られる
使わない場面
- 選択肢が 10 件以下。Select のほうが速く、モバイルで OS の標準ピッカーが使える
- 自由入力も受けたいとき。Combobox は候補にない文字を確定しない。Input を使う
- 複数選択。Combobox は 1 つだけ。Checkbox の並びか FilterPill を使う
- 操作を探すこと(コマンド、ページ移動)。CommandPalette を使う
使い方
import { Combobox, FormField } from "kaze-design-system";
const options = [
{ value: "tokyo", label: "東京都", keywords: ["とうきょう"] },
{ value: "osaka", label: "大阪府", keywords: ["おおさか"] },
];
<FormField label="都道府県" error={error}>
<Combobox
name="prefecture"
options={options}
value={prefecture}
onValueChange={setPrefecture}
/>
</FormField>プロパティ
| 名前 | 型 | デフォルト | 説明 |
|---|---|---|---|
options必須 | ComboboxOption[] | なし | 候補。keywords は表示せず検索だけに使う読みや別名 |
value | string | null | なし | 選択中の value(制御)。未選択は null |
defaultValue | string | null | null | 初期の選択(非制御) |
onValueChange | (value: string | null) => void | なし | 選択が変わる時のコールバック。入力を空にして離れると null |
filter | (option: ComboboxOption, query: string) => boolean | なし | 絞り込みの差し替え。既定は label と keywords への includesJa |
name | string | なし | 指定すると hidden input で value(ラベルではなく)をフォーム送信する |
size | "sm" | "md" | "md" | サイズ |
emptyMessage | string | "候補がありません" | 一致する候補がないときの文言 |
wrapperClassName | string | なし | 外側の要素に足すクラス |
aria-invalid | boolean | 'true' | 'false' | なし | true で Input と同じエラー表示。FormField の error から自動で渡される |
型と必須かどうかはソースの型定義から自動で生成しています。表にない HTML 標準の属性(className や aria-* など)も、ルート要素にそのまま渡せます。
キーボード操作
| キー | 動作 |
|---|---|
| ↓ / ↑ | 一覧を開き、候補を移動する。端では反対側へ回る。無効な候補は飛ばす |
| Home / End | 一覧が開いているとき、最初と最後の候補へ移る |
| Enter | ハイライト中の候補を選ぶ(フォームは送信されない) |
| Esc | 一覧を閉じ、入力を選択中のラベルに戻す |
| Tab | 一覧を閉じて次へ移る。ラベルと一致する文字は選択として扱う |
アクセシビリティ
- input に role="combobox"、一覧に role="listbox"、候補に role="option" を付け、ハイライトは aria-activedescendant で伝える。フォーカスは常に入力欄に残る
- 候補がないとき、emptyMessage が role="status" で読まれる。文言は emptyMessage で変える
- IME の変換中は矢印キーや Enter を候補の操作として扱わない。日本語入力で候補を誤って確定しない
- 一覧の名前は aria-label で渡す。ラベルがない場合は必ず指定する
文言
- placeholder に「担当者を検索」のように、探せることを書く
- emptyMessage は「見つかりません」ではなく、次の行動が分かる文言にする(「該当する取引先がありません。綴りを変えてください」)