Listbox
単一/複数選択の一覧から選ばせる、常時展開のリスト部品です(ポップオーバー型の Combobox/Select と異なり、content パーツ自身がフォーカスを受けます)。multiple の有無で aria-multiselectable・単一/複数選択のセマンティクスを切り替えます。
fandhe-frontend-headless-ui の listbox mod が提供する構造・アクセシビリティ(WAI-ARIA・キーボード操作)・表示状態(data-*)のみを持つ unstyled 部品です。Themes 版が備える見た目は持たず、anatomy・ARIA・data-* のみを提供します。CSS は利用者が当てます。
ListboxProps(disabled/orientation)が Root/Label/Content/ItemGroup/Item/ValueText へ data-disabled(Root 由来)・data-orientation(Root/Content/ItemGroup/Item)を一律付与します。Root の disabled は Item の有効 disabled(props.disabled || Item 個別の disabled)へ伝播します(参考実装の zag.js Listbox の getItemState と同じ挙動)。Item は選択時のみ data-selected 存在属性を追加し、data-state は "open"/"closed" の既存語彙を維持します(Themes recipe がこの語彙に依存するため)。ItemText は Item の先頭 3 引数(selected_state/disabled/highlighted)と同型の data-state/data-disabled/data-highlighted を出力します。ItemGroupLabel は role="presentation" を、ItemIndicator は aria-hidden="true" を固定付与します。
キーボード操作
| キー | 対象 | 効果 |
|---|---|---|
| ArrowDown / ArrowUp | Content | 次/前の Item へ highlight を移動する(既定・非循環。fandhe-frontend-wasm-full の keynav で配線済み) |
| ArrowRight / ArrowLeft | Content(data-orientation="horizontal" のときのみ) | 次/前の Item へ highlight を移動する |
| Home / End | Content | 先頭/末尾の非 disabled Item へ highlight を移動する |
| 文字キー | Content | typeahead。連続入力したキーに前方一致する非 disabled Item へ highlight を移動する |
| Enter / Space | Content | typeahead バッファ非活性時、highlight 中の非 disabled Item へ click を合成する(選択状態を書き換える dispatch へは未接続。別イシューで対応予定) |
| Escape | Content | typeahead バッファのリセットのみを行う(選択解除は行わない。ダイアログ内 Listbox が親の Escape 閉鎖を奪わないための意図的な非対称) |
ポインタ・キーボード操作の実際の DOM 配線は fandhe-frontend-wasm-full の keynav モジュールが担います。Enter/Space による決定は highlight 中の項目への click 合成までで、選択状態を書き換える dispatch("select"/"toggle")への接続は本モジュールのスコープ外です。
スタイル済みの表示例は Listbox を参照してください。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
Themes 版を使わず本部品を直接使う場合、[data-scope="listbox"][data-part="..."] セレクタでスタイルを当てます。以下は選択・highlight・disabled 状態、横並びレイアウト、root disabled の最小例です。
[data-scope="listbox"][data-part="item"][data-selected] {
background: #dbeafe;
}
[data-scope="listbox"][data-part="item"][data-highlighted] {
outline: 2px solid #2563eb;
}
[data-scope="listbox"][data-part="item"][data-disabled] {
opacity: 0.5;
}
[data-scope="listbox"][data-part="content"][data-orientation="horizontal"] {
flex-direction: row;
}
[data-scope="listbox"][data-part="root"][data-disabled] {
opacity: 0.5;
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- root/label/content/item_group/item_group_label/item/item_text/item_indicator/value_text の anatomy を持ち、content 自身がフォーカスを受ける常時展開のリストである(crate::combobox/select のようなポップオーバー型とは異なる、listbox.rs:1-9, 64)。
- ListboxProps(disabled/orientation)を root/label/content/item_group/item/value_text へ一律付与する(参照突合、イシュー #1611、listbox.rs:147-177)。root の disabled は item の有効 disabled(props.disabled || item 個別の disabled)へ伝播する(listbox.rs:385-421)。
- content は role="listbox" + tabindex="0" を固定付与し、multiple のとき aria-multiselectable="true" を付与する(single モードでは省略、listbox.rs:281-317)。
- item は role="option" + aria-selected + data-state("open"/"closed")を固定付与し、選択時のみ data-selected 存在属性を追加する。disabled のとき aria-disabled="true" と data-disabled を対で付与する(div[role="option"] はネイティブ disabled を持たないため、listbox.rs:385-421)。
- item_text は selected_state/disabled/highlighted の 3 状態を data-state/data-disabled/data-highlighted として出力する(item の先頭 3 引数と同型、listbox.rs:431-457)。
- item_group_label は role="presentation" を、item_indicator は aria-hidden="true" を固定付与する(参照突合、イシュー #1611、listbox.rs:347-384, 458-483)。
- activedescendant が Some のとき content へ aria-activedescendant を付与し、現在ハイライト中の item の id と対応させる(listbox.rs:281-317)。
Anatomy
root
label
content
item-group
item-group-label
item
item-text
item-indicator
value-textAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
ListboxProps { disabled, orientation } | bool, Orientation | disabled=false, orientation=Vertical | root/content/item_group/item へ data-orientation を、root/label/content/item_group/item/value_text へ data-disabled 系を一律付与する(listbox.rs:147-177)。 |
root(selection_state, props) | OpenState, &ListboxProps | — | 選択有無を data-state へ、props を data-orientation/data-disabled へ反映する(listbox.rs:233-247)。 |
content(multiple, props, id, labelledby, activedescendant) | bool, &ListboxProps, Option<&str>, Option<&str>, Option<&str> | — | aria-multiselectable/aria-labelledby/aria-activedescendant の各付与条件(listbox.rs:281-317)。 |
item(selected_state, props, disabled, highlighted, value, id) | OpenState, &ListboxProps, bool, bool, &str, Option<&str> | — | role="option" を持つ選択肢 1 個の状態。有効 disabled は props.disabled || disabled。value は data-value として既定エスケープ経由で出力される(listbox.rs:385-421)。 |
item_text(selected_state, props, disabled, highlighted, id) | OpenState, &ListboxProps, bool, bool, Option<&str> | — | item の先頭 3 引数と同型の 3 状態属性。有効 disabled は item と同じ props.disabled || disabled を内部で計算する(listbox.rs:431-462)。 |
attrs / children | Vec<(&str, &str)> / Vec<Node> | — | 各パーツ共通の追加属性・子ノード(代表 1 行に集約)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
content | data-disabled | (値なし) |
content | data-orientation | horizontal, vertical |
item | data-disabled | (値なし) |
item | data-highlighted | (値なし) |
item | data-orientation | horizontal, vertical |
item | data-selected | (値なし) |
item | data-state | closed, open |
item | data-value | apple, banana, cheddar, cherry, mozzarella |
item-group | data-disabled | (値なし) |
item-group | data-orientation | horizontal, vertical |
item-indicator | data-state | closed, open |
item-text | data-disabled | (値なし) |
item-text | data-highlighted | (値なし) |
item-text | data-state | closed, open |
label | data-disabled | (値なし) |
root | data-disabled | (値なし) |
root | data-orientation | horizontal, vertical |
root | data-state | open |
value-text | data-disabled | (値なし) |
Examples
Multiple selection
aria-multiselectable="true" の Listbox の組み立て例です。
multiple=true(aria-multiselectable="true")の Listbox の組み立て例です。
自前 CSS の最小例
headless-ui 自体はスタイルを持たないため、data-* 属性セレクタで見た目を組み立てる最小例です。
利用者が data-scope / data-part / data-state / data-selected / data-orientation / data-disabled 属性セレクタで自前 CSS を当てる最小例です。headless-ui 自体はスタイルを持ちません。
[data-scope="listbox"][data-part="item"][data-selected] {
background: #dbeafe;
}
[data-scope="listbox"][data-part="item"][data-highlighted] {
outline: 2px solid #2563eb;
}
[data-scope="listbox"][data-part="item"][data-disabled] {
opacity: 0.5;
}
[data-scope="listbox"][data-part="content"][data-orientation="horizontal"] {
flex-direction: row;
}
[data-scope="listbox"][data-part="root"][data-disabled] {
opacity: 0.5;
}
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| ArrowDown / ArrowUp | content にフォーカス時: 次/前の item へ highlight を移動する(既定・非循環。fandhe-frontend-wasm-full の keynav::handle_listbox_keydown で配線済み、イシュー #1070)。 |
| ArrowRight / ArrowLeft | content の data-orientation="horizontal" のときのみ、次/前の item へ highlight を移動する(fandhe-frontend-wasm-full の keynav で配線済み)。 |
| Home / End | content にフォーカス時: 先頭/末尾の非 disabled item へ highlight を移動する(fandhe-frontend-wasm-full の keynav で配線済み)。 |
| 文字キー | typeahead。連続入力したキーに前方一致する非 disabled item へ highlight を移動する(fandhe-frontend-wasm-full の keynav で配線済み)。 |
| Enter / Space | typeahead バッファ非活性時、highlight 中の非 disabled item へ click を合成する(fandhe-frontend-wasm-full の keynav で配線済み)。ただし選択状態を書き換える dispatch("select"/"toggle")へは未接続(headless.rs::MAPPING_TABLE に listbox 行が無いため、スコープ外・別イシュー化を提案)。 |
| Escape | typeahead バッファのリセットのみを行う(prevent_default せず選択解除も行わない。ダイアログ内 Listbox が親の Escape 閉鎖を奪わないための意図的な非対称、listbox.rs module doc 参照)。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| role="listbox" | content パーツへ固定付与する(listbox.rs:281-317)。 |
| aria-multiselectable | multiple が true のときのみ "true" を付与する(listbox.rs:281-317)。 |
| aria-labelledby | content の labelledby が Some のときのみ付与する(listbox.rs:281-317)。 |
| role="option" / aria-selected / aria-disabled | item パーツへ固定付与する(aria-disabled は有効 disabled が true のときのみ、listbox.rs:385-421)。 |
| role="presentation" | item_group_label パーツへ固定付与する(zag の ItemGroupLabel anatomy に合わせる、listbox.rs:347-384)。 |
| aria-hidden="true" | item_indicator パーツへ固定付与する(item 自身の aria-selected が選択状態を既に伝達するため、支援技術の二重読み上げを防ぐ、listbox.rs:458-483)。 |