Select
Select
A combobox trigger built on the same field chrome as TextField, with a width-matched listbox popup.
import { useState } from 'react'
import { Icon, Select, Surface, Text } from '@language-lit/material3-expressive'
const fruitOptions = [
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'cherry', label: 'Cherry' },
{ value: 'durian', label: 'Durian', disabled: true },
]
export function SelectExample() {
const [filledValue, setFilledValue] = useState('apple')
const [outlinedValue, setOutlinedValue] = useState('')
return (
<Surface
as="section"
aria-labelledby="select-example-title"
color="surface-container-low"
shape="extra-large"
className="select-example"
>
<Text as="h2" id="select-example-title" variant="titleLarge" emphasis="emphasized">
Select
</Text>
<Text as="p" variant="bodyMedium">
A combobox trigger built on the same field chrome as TextField, with
a width-matched listbox popup.
</Text>
<div className="select-example__row">
<Select
label="Favorite fruit"
variant="filled"
leadingIcon={<Icon source="nutrition" />}
options={fruitOptions}
value={filledValue}
onValueChange={setFilledValue}
supportingText="One disabled option"
name="favorite-fruit"
/>
<Select
label="Outlined select"
variant="outlined"
options={fruitOptions}
value={outlinedValue}
onValueChange={setOutlinedValue}
/>
<Select label="Disabled" options={fruitOptions} defaultValue="banana" disabled />
</div>
<div className="select-example__row">
<Select
label="Outlined with icon"
variant="outlined"
leadingIcon={<Icon source="nutrition" />}
options={fruitOptions}
defaultValue="cherry"
/>
<Select
label="Invalid selection"
options={fruitOptions}
defaultValue="banana"
error
supportingText="Out of stock, please choose another"
/>
<Select
label="Disabled outlined"
variant="outlined"
options={fruitOptions}
defaultValue="banana"
disabled
/>
</div>
<div className="select-example__row">
<Select
label="Statically open"
options={fruitOptions}
defaultValue="apple"
defaultOpen
supportingText="Rendered open to preview the listbox, including the disabled option"
/>
</div>
</Surface>
)
}Selectはデータ駆動型のcomboboxです。TextFieldと同じ装飾を持つ読み取り専用のトリガーフィールドと、Menuと同じ装飾を持つポップアップリストボックスで構成します。ネイティブの<select>要素は使いません。ライブラリが対応するブラウザー範囲では、ネイティブ<select>のポップアップ内にMaterial独自の選択肢行を一貫してスタイル設定できないためです。
import { Select } from '@language-lit/material3-expressive'
import '@language-lit/material3-expressive/styles.css'
<Select
label="Favorite fruit"
options={[
{ value: 'apple', label: 'Apple' },
{ value: 'banana', label: 'Banana' },
{ value: 'cherry', label: 'Cherry' },
]}
value={value}
onValueChange={setValue}
/>仕様
value/defaultValue/onValueChange(いずれもstring)は、ほかの状態を持つコンポーネントと同じ制御/非制御の形式です。options: readonly SelectOption[]は{ value, label: string, disabled? }の形式です。labelはプレーンな文字列です。トリガー上に選択値として表示するためで、ネイティブ<select>の<option>もテキストであるのと同様です。label、variant(既定値"filled"、または"outlined")、leadingIcon、supportingText、error、disabledは、TextFieldと同じprop名と既定値です。open/defaultOpen/onOpenChangeでポップアップリストボックスを制御できます。直接監視または操作したい場合に使います。- refはトリガーとなる入力を参照します。
classNameとstyleはフィールドのルートに適用されます。
トリガーは読み取り専用入力ですが、TextFieldと同じ個別の論理方向の先頭/コンテンツ/末尾領域を持ちます。任意の先頭アイコンと必須の末尾シェブロンは入力領域の外にそれぞれの幅を確保します。利用側のCSSで入力余白をリセットしても、表示値とブラウザー標準の入力領域がアイコンに重なりません。上/コンテンツ/下のグリッド行も共通で、filled/outlinedのラベルと値の位置はネイティブ入力のブロック余白に依存しません。
キーボード操作
閉じているときにEnter、Space、ArrowDown、ArrowUpを押すとリストボックスを開き、現在の選択肢(選択がなければ有効な最初または最後の選択肢)をアクティブにします。開いているときはArrowDown/ArrowUp/Home/Endでアクティブな選択肢を移動し、文字入力で先頭一致に移動します。Enter/Spaceで確定して閉じます。Escapeは値を変更せずに閉じ、Tabでも閉じます。
Menuとは異なり、フォーカスはトリガーから移動しません。現在ハイライトされている選択肢はaria-activedescendantで追跡します。これは、Menuのように各項目へ実際のフォーカスを移すのではなく、WAI-ARIA APGのselect-only comboboxパターンに従っています。
フォーム
<Select label="Favorite fruit" name="favorite-fruit" options={options} defaultValue="apple" />nameを指定すると、現在の値を持つ補助的な<input type="hidden">が出力されます。表示コントロールは値を送信しない読み取り専用入力ですが、これによりSelectはネイティブのフォーム送信、FormData、form.reset()に参加できます。
トークンと境界
Select独自のコンポーネントトークンは登録しません。フィールド装飾はTextFieldの--m3e-comp-text-field-*登録を、ポップアップのリストボックスはMenuの--m3e-comp-menu-*登録をそのまま再利用します。どちらのテーマ上書きもMaterial3Providerのスコープ内で適用されます。Selectは実行時スタイルを注入せず、Next.js、Vite、ルーター、アニメーションライブラリ、非公開のアプリケーションコードをインポートしません。