Skip to content

選取與 tagging

單選與多選

預設是單選。設定 multiple: true 改為多選,已選項會渲染成可移除的 tag:

js
createSelkit({ options, multiple: true })

綁定值在單選時是單值,多選時是陣列。

多選模式下,點擊選項(或在其上按 Enter)會 toggle:點擊已選的選項會取消選取, 而不只能透過 tag 移除。

開啟 restoreOnBackspace 後,輸入框為空時按 Backspace 會刪除最後一個 tag 並把其 label 回填輸入框(同時開啟下拉),讓你直接編輯而不必重打。未開啟(預設)時 Backspace 只會刪除該 tag。

Highlight

開啟下拉與每次搜尋後,第一個可選項會自動 highlight,作為鍵盤導覽起點(Enter 直接選取、方向鍵從此移動)。設 highlightFirst: false 可關閉——下拉開啟時不 highlight,只有鍵盤移動才帶出 highlight:

js
createSelkit({ options, highlightFirst: false })

無論哪種,選取一個選項後會清除 highlight(不會殘留在剛選的項上);鍵盤 Enter 則保持位置,所以能再按一次 Enter 取消該項。收合/展開分組或樹狀節點時,只要被 highlight 的項還在可見清單中就會保留。

分組

把選項用標題分組,傳入 SelkitGroup。分組標題不可選——只有葉(最末層)選項能選:

js
createSelkit({
  options: [
    { label: '水果', options: [{ value: 'a', label: 'Apple' }] },
    { label: '蔬菜', options: [{ value: 'c', label: 'Carrot' }] },
  ],
})

多層分組

options 可再接一個 SelkitGroup,因此分組可無限巢狀。每一層縮排 --selkit-level-indent(預設 16px),由每列的 --selkit-depth 驅動;中間層標題維持 不可選,只有葉帶 value:

js
createSelkit({
  options: [
    {
      label: '電子',
      options: [
        { label: '電腦', options: [
          { value: 'mbp', label: 'MacBook Pro' },
          { value: 'mba', label: 'MacBook Air' },
        ]},
        { value: 'ip15', label: 'iPhone 15' },
      ],
    },
  ],
})

搜尋多層清單時,命中葉的祖先標題會保留下來,讓命中項留在層級脈絡中;無命中的分支則 收闔消失。在 .selkit(或任一祖先)調整縮排:

css
.selkit { --selkit-level-indent: 20px; }

分組的 disabled 會向下傳遞到所有子孫。

折疊分組

給分組加上 collapsible: true,標題就變成可點擊——收合後會隱藏該分組的選項,但標題仍顯示(且依然不可選)。搭配 defaultCollapsed: true 可讓分組初始就收合:

js
createSelkit({
  options: [
    {
      label: '電子',
      collapsible: true,
      options: [
        { value: 'ip15', label: 'iPhone 15' },
        {
          label: '電腦',
          collapsible: true,
          defaultCollapsed: true,
          options: [
            { value: 'mbp', label: 'MacBook Pro' },
            { value: 'mba', label: 'MacBook Air' },
          ],
        },
      ],
    },
  ],
})

點擊可折疊標題會呼叫 controller.toggleGroup(groupKey)groupKey 可從 getGroupedView() 的每個 group row 取得。搜尋時會暫時展開所有分組讓命中項可達;清空查詢則恢復原本的收合狀態。與樹狀模式不同:折疊的分組是純標題,永遠無法被選取。

樹狀模式 tree

選項帶 children 時,select 會進入 樹狀模式:每個節點(父或葉)都有 value、 都可選;父節點透過 controller.toggleExpanded(value) 展開/收合。這與 SelkitGroup(不可選的標題)不同:children 讓父節點本身成為可選項。

js
createSelkit({
  multiple: true,
  options: [
    { value: 'elec', label: '電子', children: [
      { value: 'pc', label: '電腦', children: [
        { value: 'mbp', label: 'MacBook Pro' },
        { value: 'mba', label: 'MacBook Air' },
      ]},
    ]},
  ],
})

父節點可選。treeCascade: true(預設,僅多選)下,選父會勾選所有子孫葉,部分勾選時父 顯示半選狀態;設 treeCascade: false 為獨立選取。預設全部展開。搜尋會過濾樹並自動展開 命中節點的祖先(清空查詢恢復)。樹狀模式支援虛擬捲動(設 virtualScroll: true,與扁平 清單一致);收合與搜尋會重算可視窗格。

checkbox 選項

若要做「已選項仍顯示並打勾」的多選,啟用 checkboxes(DOM config 選項/Vue · React prop)。它會加上 selkit--checkboxes modifier class;內建主題會依 aria-selected 在每個選項渲染打勾框,無需額外標記:

js
createSelkit({ options, multiple: true, checkboxes: true })
// React:  <SelkitSelect multiple checkboxes ... />
// Vue:    <SelkitSelect multiple checkboxes ... />

僅多選生效(單選忽略),並建議搭配 hideSelected 關閉(預設)讓已選項留在清單。 若不使用內建主題,可自行為 .selkit--checkboxes .selkit__option 設定打勾樣式。

選取上限

限制一次最多可選幾項:

js
createSelkit({ options, multiple: true, maxSelections: 3 })

達到上限後,後續的 select 呼叫會被忽略。

摺疊 tag

多選項目很多時,一整排 tag 會撐爆控制項。maxSelectedDisplay 只顯示前 N 個 tag, 其餘摺疊成 +M 標記;點擊展開全部、再點(-M)收合:

js
createSelkit({ options, multiple: true, maxSelectedDisplay: 5 })

未設(預設)時顯示全部 tag。僅多選生效,且純粹是顯示層 — 已選集合本身不受影響, value 仍持有所有已選項。

隱藏已選

開啟 hideSelected 後,已選項會從下拉清單移除 — 多選 UI 常見做法。已選的值會被過濾出 visibleOptions,因此 getGroupedView() 會略過它們,所有 adapter 不需任何特別的程式 碼即可隱藏:

js
createSelkit({ options, multiple: true, hideSelected: true })

取消選取後,該項會回到清單。

Tagging

taggablecreateTag factory,允許使用者建立尚不存在的選項:

js
createSelkit({
  options,
  taggable: true,
  createTag: (query) => ({ value: query.toLowerCase(), label: query }),
})

在沒有相符選項時按 Enter 會建立並選取新 tag,並觸發 create 事件。若已存在同名 label 的選項,則改為選取既有選項,不會重複建立。

驗證 tag

傳入 isValidToken 來控管什麼能成為 tag。回傳 false 即靜默拒絕——Enter 或分隔符都不會 建立 tag,建立列也會隱藏——行為與未達 minInputLength 時一致:

js
createSelkit({
  multiple: true,
  taggable: true,
  createTag: (query) => ({ value: query.toLowerCase(), label: query }),
  // 例如只允許看起來合法的 email
  isValidToken: (query) => /.+@.+\..+/.test(query),
})

可見的「建立」列

開啟 taggable 且查詢無精確相符時,下拉會在最後顯示一列可點的建立列 (例如 Add "foo")— 使用者可用滑鼠建立 tag,而不只是按 Enter。該列可用鍵盤導航 (↑/↓/Home/End),選取它即呼叫 createTag()。當查詢為空、未達 minInputLength、 與某選項精確同名、已達 maxSelections、或 isValidToken 拒絕該查詢時不顯示。文字可用 create 訊息自訂:

js
createSelkit({
  multiple: true,
  taggable: true,
  createTag: (query) => ({ value: query.toLowerCase(), label: query }),
  messages: { create: (query) => `建立「${query}」` },
})

getGroupedView() 的視圖中,該列為 { type: 'create', index, query, label }; adapter 會自動渲染。

分隔符(token separators)

多選模式下,tokenSeparators 會在偵測到分隔符時即時把打字或貼上的文字切成 tag — 特別適合貼上逗號或空白分隔的清單:

js
createSelkit({
  options,
  multiple: true,
  taggable: true,
  createTag: (query) => ({ value: query.toLowerCase(), label: query }),
  tokenSeparators: [',', ' '],
})

打字或貼上 apple, banana, ch 會選取 applebanana(比對既有選項,或在 taggable 時建立為 tag),並把 ch 留在輸入框。未開 taggable 時,無相符的 token 會被丟棄。 Vue/React 元件亦提供同名 prop。

重新排序 tag

moveSelected(from, to) 以不可變方式重排已選陣列,並以新順序觸發 change。adapter 把 它接上拖放:tag 為 draggable,把一個 tag 放到另一個上即呼叫 moveSelected

js
controller.moveSelected(0, 2) // 把第一個 tag 移到索引 2

清除

clear() 會移除所有選取;clearable 選項(單選預設 true)會在 indicators 區顯示清除鈕。

為避免誤觸清空,設定 clearConfirm:第一次點擊會進入「確認」狀態(按鈕變成紅色 Confirm),只有第二次點擊才真正清除。閒置 2.5 秒後自動復原:

js
createSelkit({ options, multiple: true, clearable: true, clearConfirm: true })

clearConfirmText 可覆寫確認按鈕的文字(同時用於顯示與 aria-label,預設 "Confirm")— 方便做 i18n:

js
createSelkit({
  options,
  multiple: true,
  clearable: true,
  clearConfirm: true,
  clearConfirmText: '確認清空',
})

依 MIT 授權釋出。