Skip to content
fandhe-frontendcore v0.4.3
GitHub

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 / ArrowUpContent次/前の Item へ highlight を移動する(既定・非循環。fandhe-frontend-wasm-full の keynav で配線済み)
ArrowRight / ArrowLeftContent(data-orientation="horizontal" のときのみ)次/前の Item へ highlight を移動する
Home / EndContent先頭/末尾の非 disabled Item へ highlight を移動する
文字キーContenttypeahead。連続入力したキーに前方一致する非 disabled Item へ highlight を移動する
Enter / SpaceContenttypeahead バッファ非活性時、highlight 中の非 disabled Item へ click を合成する(選択状態を書き換える dispatch へは未接続。別イシューで対応予定)
EscapeContenttypeahead バッファのリセットのみを行う(選択解除は行わない。ダイアログ内 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 の最小例です。

CSS
[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 自体はスタイルを持ちません。

Common
Apple
Banana
Cherry (disabled)
Apple
Cheddar
Mozzarella
2 selected

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-text

API Reference

Arguments

NameTypeDefaultDescription
ListboxProps { disabled, orientation }bool, Orientationdisabled=false, orientation=Verticalroot/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 / childrenVec<(&str, &str)> / Vec<Node>—各パーツ共通の追加属性・子ノード(代表 1 行に集約)。

Data Attributes

PartAttributeObserved Values
contentdata-disabled(値なし)
contentdata-orientationhorizontal, vertical
itemdata-disabled(値なし)
itemdata-highlighted(値なし)
itemdata-orientationhorizontal, vertical
itemdata-selected(値なし)
itemdata-stateclosed, open
itemdata-valueapple, banana, cheddar, cherry, mozzarella
item-groupdata-disabled(値なし)
item-groupdata-orientationhorizontal, vertical
item-indicatordata-stateclosed, open
item-textdata-disabled(値なし)
item-textdata-highlighted(値なし)
item-textdata-stateclosed, open
labeldata-disabled(値なし)
rootdata-disabled(値なし)
rootdata-orientationhorizontal, vertical
rootdata-stateopen
value-textdata-disabled(値なし)

Examples

Multiple selection

aria-multiselectable="true" の Listbox の組み立て例です。

multiple=true(aria-multiselectable="true")の Listbox の組み立て例です。

Japan
United States

自前 CSS の最小例

headless-ui 自体はスタイルを持たないため、data-* 属性セレクタで見た目を組み立てる最小例です。

利用者が data-scope / data-part / data-state / data-selected / data-orientation / data-disabled 属性セレクタで自前 CSS を当てる最小例です。headless-ui 自体はスタイルを持ちません。

Apple
CSS
[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

KeyDescription
ArrowDown / ArrowUpcontent にフォーカス時: 次/前の item へ highlight を移動する(既定・非循環。fandhe-frontend-wasm-full の keynav::handle_listbox_keydown で配線済み、イシュー #1070)。
ArrowRight / ArrowLeftcontent の data-orientation="horizontal" のときのみ、次/前の item へ highlight を移動する(fandhe-frontend-wasm-full の keynav で配線済み)。
Home / Endcontent にフォーカス時: 先頭/末尾の非 disabled item へ highlight を移動する(fandhe-frontend-wasm-full の keynav で配線済み)。
文字キーtypeahead。連続入力したキーに前方一致する非 disabled item へ highlight を移動する(fandhe-frontend-wasm-full の keynav で配線済み)。
Enter / Spacetypeahead バッファ非活性時、highlight 中の非 disabled item へ click を合成する(fandhe-frontend-wasm-full の keynav で配線済み)。ただし選択状態を書き換える dispatch("select"/"toggle")へは未接続(headless.rs::MAPPING_TABLE に listbox 行が無いため、スコープ外・別イシュー化を提案)。
Escapetypeahead バッファのリセットのみを行う(prevent_default せず選択解除も行わない。ダイアログ内 Listbox が親の Escape 閉鎖を奪わないための意図的な非対称、listbox.rs module doc 参照)。

WAI-ARIA

AttributeDescription
role="listbox"content パーツへ固定付与する(listbox.rs:281-317)。
aria-multiselectablemultiple が true のときのみ "true" を付与する(listbox.rs:281-317)。
aria-labelledbycontent の labelledby が Some のときのみ付与する(listbox.rs:281-317)。
role="option" / aria-selected / aria-disableditem パーツへ固定付与する(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)。