輸入元件
下拉選擇器
按鈕觸發的選擇器:目前值交叉淡接、選單錨定並在邊緣翻轉,群組與分隔、首字跳轉與方向鍵巡覽,高亮列滑動。
以按鈕觸發的下拉選擇器,選項用資料陣列傳入。換值時觸發鈕上的文字交叉淡接;選單以 portal 錨定在觸發鈕旁,空間不足時自動翻到對側並沿邊緣平移,太長時出現上下捲動提示。支援群組與分隔線、停用項、首字跳轉、方向鍵/Home/End 巡覽,高亮背景會在選項之間滑動。值與開關狀態都支援受控/非受控,給 name 即可直接搭配原生表單送出。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add selectPlayground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
100
編輯中的呼叫預設屬性
<Select/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
安裝
npx webberui@latest add https://webberui.com/r/select.json或在 components.json 設定 registries 後,改用 @webberui/select 安裝。
使用
import { Select } from "@/components/ui/select";
const [language, setLanguage] = React.useState("zh-TW");
<Select
aria-label="介面語言"
value={language}
onValueChange={setLanguage}
options={[
{ value: "zh-TW", label: "繁體中文(台灣)" },
{ value: "en", label: "English" },
{ value: "ja", label: "日本語" },
]}
/>
// 分組:群組之間自動插入分隔線
<Select
aria-label="時區"
name="timezone"
placeholder="選擇時區"
groups={[
{ label: "亞洲", options: [{ value: "Asia/Taipei", label: "台北(UTC+8)" }] },
{ label: "歐洲", options: [{ value: "Europe/London", label: "倫敦(UTC+0)" }] },
]}
/>Props
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
options | SelectOption[] | — | 選項清單(扁平);與 groups 擇一,兩者都給時 groups 優先 |
groups | SelectGroup[] | — | 分組選項;群組之間自動插入分隔線 |
value | string | — | 受控的目前值;未提供時由元件內部管理(非受控) |
defaultValue | string | — | 非受控模式的初始值 |
onValueChange | (value: string) => void | — | 選取值變動時回呼 |
open | boolean | — | 受控的開啟狀態 |
defaultOpen | boolean | false | 非受控模式的初始開啟狀態 |
onOpenChange | (open: boolean) => void | — | 開啟狀態變動時回呼 |
placeholder | string | "請選擇" | 尚未選值時顯示的佔位文字 |
disabled | boolean | false | 停用整個選擇器 |
name | string | — | 表單欄位名稱;有值時渲染 hidden input,讓原生表單送出時帶上目前值 |
size | "sm" | "md" | "md" | 觸發鈕尺寸 |
duration | number | 100 | 浮層進出場時長(毫秒);同時寫入 --wb-select-duration 供 CSS 轉場使用 |
side | "top" | "right" | "bottom" | "left" | "bottom" | 浮層偏好的方位,空間不足時自動翻到對側 |
align | "start" | "center" | "end" | "start" | 浮層在交叉軸上的對齊方式 |
sideOffset | number | 4 | 浮層與觸發鈕之間的距離(px) |
aria-label | string | — | 觸發鈕與清單的無障礙名稱 |
triggerClassName | string | — | 額外套用到觸發鈕的 class |
className | string | — | 透傳到根元素 |
SelectOption
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
value | string | — | 選項值(表單送出與 onValueChange 回傳的值) |
label | string | — | 顯示文字,也是首字跳轉比對的對象 |
icon | ReactNode | — | 文字前的圖示 |
disabled | boolean | false | 停用此選項:無法選取,方向鍵與首字跳轉會略過 |
group | string | — | 所屬群組名稱;只在使用 options 時生效,同名選項會被收在同一群組 |
SelectGroup
| 欄位 | 型別 | 預設值 | 說明 |
|---|---|---|---|
label | string | — | 群組標題 |
options | SelectOption[] | — | 群組內的選項 |
細節
- 定位:浮層以
position: fixedportal 到body,依side/align/sideOffset放在觸發鈕外側;主軸溢出且對側空間較大時翻轉,交叉軸則平移回視窗內(距邊緣 8px)。觸發鈕或浮層尺寸改變、視窗縮放、任何祖先捲動時都會重算,同一幀只算一次。浮層帶data-side/data-align,方便依實際落點寫樣式。 - 尺寸:寬度取觸發鈕寬與內容寬的較大者;高度上限 18rem 且不超過視窗可用空間,超出時清單可捲動,頂/底出現捲動提示,滑鼠停在提示上會持續捲動。
- 動畫:進場為淡入、從 0.95 放大並沿方位反方向滑入 8px,縮放原點依翻轉後的實際落點設定;關閉為同一組值反向。
duration同時寫入 CSS 變數--wb-select-duration,觸發鈕箭頭的旋轉等 CSS 轉場都讀它,可在全域覆寫。觸發鈕上的文字換值時以 1.5 倍時長交叉淡接。 - 首字跳轉:500ms 內連續打字會累加前綴比對選項開頭,中文以首字比對;連按同一個字會在同字首的選項間輪替。觸發鈕聚焦但未開啟時直接打字就會改值,與原生 select 一致;IME 組字中的按鍵一律略過。
- 給
name時會渲染<input type="hidden">,原生表單送出就帶上目前值。
可及性
- 觸發鈕為
role="combobox"、aria-haspopup="listbox",以aria-expanded/aria-controls指向清單;請提供aria-label作為名稱 - 清單為
role="listbox",開啟時取得焦點並以aria-activedescendant指向高亮項;選項為role="option",帶aria-selected與aria-disabled;群組為role="group"並以aria-labelledby關聯標題 - 鍵盤:Enter、Space、↑、↓ 開啟;↑/↓ 移動高亮(略過停用項、不循環)、Home/End 跳到首尾;Enter/Space 選取並關閉、Tab 選取目前高亮並離開、Escape 關閉不改值;關閉後焦點回到觸發鈕
- 點擊浮層外任何位置即關閉
- 使用者系統開啟「減少動態效果」時,浮層與換值只保留淡入淡出、不縮放不位移,高亮列直接跳到新位置