輸入元件

下拉選擇器

按鈕觸發的選擇器:目前值交叉淡接、選單錨定並在邊緣翻轉,群組與分隔、首字跳轉與方向鍵巡覽,高亮列滑動。

以按鈕觸發的下拉選擇器,選項用資料陣列傳入。換值時觸發鈕上的文字交叉淡接;選單以 portal 錨定在觸發鈕旁,空間不足時自動翻到對側並沿邊緣平移,太長時出現上下捲動提示。支援群組與分隔線、停用項、首字跳轉、方向鍵/Home/End 巡覽,高亮背景會在選項之間滑動。值與開關狀態都支援受控/非受控,給 name 即可直接搭配原生表單送出。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add select

還沒有專案,或安裝遇到問題?看快速開始 →

Playground

即時調整 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型別預設值說明
optionsSelectOption[]—選項清單(扁平);與 groups 擇一,兩者都給時 groups 優先
groupsSelectGroup[]—分組選項;群組之間自動插入分隔線
valuestring—受控的目前值;未提供時由元件內部管理(非受控)
defaultValuestring—非受控模式的初始值
onValueChange(value: string) => void—選取值變動時回呼
openboolean—受控的開啟狀態
defaultOpenbooleanfalse非受控模式的初始開啟狀態
onOpenChange(open: boolean) => void—開啟狀態變動時回呼
placeholderstring"請選擇"尚未選值時顯示的佔位文字
disabledbooleanfalse停用整個選擇器
namestring—表單欄位名稱;有值時渲染 hidden input,讓原生表單送出時帶上目前值
size"sm" | "md""md"觸發鈕尺寸
durationnumber100浮層進出場時長(毫秒);同時寫入 --wb-select-duration 供 CSS 轉場使用
side"top" | "right" | "bottom" | "left""bottom"浮層偏好的方位,空間不足時自動翻到對側
align"start" | "center" | "end""start"浮層在交叉軸上的對齊方式
sideOffsetnumber4浮層與觸發鈕之間的距離(px)
aria-labelstring—觸發鈕與清單的無障礙名稱
triggerClassNamestring—額外套用到觸發鈕的 class
classNamestring—透傳到根元素

SelectOption

欄位型別預設值說明
valuestring—選項值(表單送出與 onValueChange 回傳的值)
labelstring—顯示文字,也是首字跳轉比對的對象
iconReactNode—文字前的圖示
disabledbooleanfalse停用此選項:無法選取,方向鍵與首字跳轉會略過
groupstring—所屬群組名稱;只在使用 options 時生效,同名選項會被收在同一群組

SelectGroup

欄位型別預設值說明
labelstring—群組標題
optionsSelectOption[]—群組內的選項

細節

  • 定位:浮層以 position: fixed portal 到 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 關閉不改值;關閉後焦點回到觸發鈕
  • 點擊浮層外任何位置即關閉
  • 使用者系統開啟「減少動態效果」時,浮層與換值只保留淡入淡出、不縮放不位移,高亮列直接跳到新位置