輸入元件

可搜尋選擇器

輸入即篩選的選擇器:注音組字中不過濾也不誤選,清單錨定並在邊緣翻轉,高亮列滑動,多選時選項化成可移除的標籤。

這是 WebberUI Pro 元件

下方的安裝指令需要授權才能執行,未授權時會回 401。

怎麼安裝 Pro 元件 →查看方案 →

選項一多,下拉選單就該能打字找。這個 Combobox 把繁中輸入當成第一優先:用注音打「ㄊㄞˊ」時清單維持原樣、不跟著半成品亂跳,選完字才篩選;組字中按 Enter、方向鍵、Backspace 都交給輸入法,不會誤選或誤刪。預設比對把「臺」與「台」視為同一字,並可用 keywords 補英文名或別名。清單錨定在輸入框下方、下方空間不足時翻到上方,高亮列在選項間滑動;切成 multiple 後,選中的項目化成可移除的標籤,creatable 還能直接新增清單裡沒有的項目。

把這個效果裝進你的專案

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

npx webberui@latest add "https://webberui.com/r/combobox.json?t=<安裝 token>"

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

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

100
編輯中的呼叫預設屬性
<Combobox/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

安裝

npx webberui@latest add "https://webberui.com/r/combobox.json?t=<安裝 token>"

或在 components.json 設定 registries 後,改用 @webberui/combobox 安裝。

使用

import { Combobox, type ComboboxOption } from "@/components/ui/combobox";

const cities: ComboboxOption[] = [
  { value: "taipei", label: "臺北市", group: "北部", keywords: ["Taipei"] },
  { value: "taichung", label: "臺中市", group: "中部", keywords: ["Taichung"] },
  { value: "kaohsiung", label: "高雄市", group: "南部", keywords: ["Kaohsiung"] },
];

// 單選:value 為 string | null
const [city, setCity] = React.useState<string | null>(null);
<Combobox options={cities} value={city} onValueChange={setCity} aria-label="配送縣市" />;

// 多選 + 可新增:value 為 string[]
const [tags, setTags] = React.useState<string[]>([]);
const [tagOptions, setTagOptions] = React.useState<ComboboxOption[]>([
  { value: "設計", label: "設計" },
  { value: "前端", label: "前端" },
]);
<Combobox
  multiple
  creatable
  options={tagOptions}
  value={tags}
  onValueChange={setTags}
  onCreate={(label) => setTagOptions((prev) => [...prev, { value: label, label }])}
  maxVisibleChips={3}
  aria-label="感興趣的主題"
/>;

Props

Prop型別預設值說明
optionsComboboxOption[]—選項清單
multiplebooleanfalse多選模式;決定 value 系列 props 的型別
valuestring | null(多選為 string[])—受控的選取值;不提供時為非受控模式
defaultValuestring | null(多選為 string[])null/[]非受控模式的初始選取值
onValueChange(value: string | null) => void(多選為 (value: string[]) => void)—選取值變動時回呼
inputValuestring—受控的輸入框文字
onInputValueChange(value: string) => void—輸入框文字變動時回呼(含組字中的暫存文字)
filter(option: ComboboxOption, query: string) => boolean—自訂過濾;未提供時以 label 與 keywords 不分大小寫包含比對,並把「臺」視同「台」。查詢字為空時不呼叫
creatablebooleanfalse查無完全相符的項目時,在清單底部顯示「新增「xxx」」列
onCreate(label: string) => void—選了新增列時回呼;新項目以 label 當 value 加入選取,請在這裡把它加進 options
placeholderstring"搜尋或選擇…"輸入框提示文字(多選且已有標籤時不顯示)
emptyTextstring"找不到符合的項目"沒有任何符合項目時的文字
maxVisibleChipsnumber—多選時最多顯示幾個標籤,其餘收成「+N」
openboolean—受控的清單開啟狀態
defaultOpenbooleanfalse非受控模式的初始開啟狀態
onOpenChange(open: boolean) => void—清單開關時回呼
disabledbooleanfalse停用整個元件
durationnumber100清單彈出動畫長度(毫秒),同時寫入 --wb-combobox-duration
side"bottom" | "top""bottom"清單偏好方向;空間不足時自動翻到另一側
sideOffsetnumber4清單與輸入框的距離(px)
idstring—輸入框的 id,讓外部 label 以 htmlFor 指向
aria-labelstring—沒有可見標籤時的無障礙名稱
classNamestring—透傳到最外層容器

ComboboxOption

欄位型別預設值說明
valuestring—選項的值,在 options 內必須唯一
labelstring—顯示文字,也是預設比對的對象
groupstring—群組名稱;同名選項收在同一個群組標題下,依首次出現順序排列
disabledbooleanfalse照常顯示但無法選取,鍵盤巡覽會跳過
keywordsstring[]—額外比對字,例如英文名「Taipei」或異體字

另外具名匯出 ComboboxOption、ComboboxSide、ComboboxProps、ComboboxSingleProps 與 ComboboxMultipleProps 型別。

細節

  • 組字中不過濾:元件以 compositionstart/compositionend 追蹤組字狀態。組字中輸入框照常顯示注音,但用來篩選的字凍結在組字前的值,選字完成後才以最終文字重新篩選——清單不會隨「ㄊㄞ」這類半成品閃動
  • 組字中的按鍵交給輸入法:Enter、↑/↓、Backspace、Esc 都先檢查 isComposing 與 keyCode 229(Safari 在 compositionend 之後才送 keydown),組字中一律放行給輸入法選字,不會誤選、誤刪標籤
  • 開關時機:點擊輸入框、開始打字、按 ↓ 或右側箭頭鈕會開啟;Esc 第一次關清單、第二次清空輸入框;點外或 Tab 離開會關閉。單選時選取後輸入框顯示該 label;失焦時若文字被改過但沒選,會還原為已選 label;在清單中再點一次已選項可取消選取
  • 定位:清單以 portal 掛到 body、position: fixed,寬度等於輸入框外框(多選時含標籤列),下方空間不足時翻到上方;捲動與縮放視窗會以 rAF 節流重算位置,第一次量測前保持隱藏,不會閃在左上角
  • 節奏:彈出為淡入 + 縮放 0.95 + 沿方向位移 8px,預設 100ms,由 duration 控制;浮層內的 CSS 轉場讀 --wb-combobox-duration,可在全域覆寫。高亮列以共用 layoutId 彈簧滑動;多選標籤以彈簧彈入,移除時其餘標籤以 FLIP 補位
  • 新增:creatable 時,若輸入文字與現有 label 都不完全相同(同樣把「臺」視為「台」),清單底部出現新增列,按 Enter 或點擊即觸發 onCreate

可及性

  • 輸入框為 role="combobox",帶 aria-expanded、aria-controls、aria-autocomplete="list",並以 aria-activedescendant 指向目前高亮的選項;焦點始終留在輸入框,點擊清單不會失焦
  • 清單為 role="listbox"(多選時加 aria-multiselectable),選項為 role="option" 並標示 aria-selected、aria-disabled;群組以 role="group" 包住並由群組標題命名
  • ↑/↓ 循環移動高亮並跳過停用項,Home/End 跳到首末項,Enter 選取;多選時輸入框為空按 Backspace 移除最後一個標籤
  • 每個標籤的移除鈕都是可用 Tab 聚焦的按鈕,aria-label 為「移除 xxx」;結果數量由 aria-live="polite" 區域宣告(「共 N 個結果」或空狀態文字)
  • 使用者系統開啟「減少動態效果」時,清單只保留淡入(長度不變)、不縮放也不位移;高亮列與標籤直接到位,不使用彈簧與 FLIP 補位