跳至主要內容

CSS-only Tailwind CSS combobox with live search filtering and accessible dropdown list. Keyboard navigation, color variants. WCAG AA accessible, works with Django, HTMX, Laravel, React, and any stack.

組合方塊將文字輸入與下拉清單組合在一起。使用欄位的輸入組件 - 大小、顏色和狀態變體都來自那裡。 combobox-* 實用程式僅處理下拉清單、項目和開啟狀態。

僅 CSS,無需 JavaScript。 WCAG AA 可存取且與框架無關 - 可與 Django、HTMX、Laravel、React 和任何堆疊配合使用。

班級 類型 描述
combobox-list根據組合方塊選項的下拉清單容器
combobox-item修飾符下拉清單中的單一選項
combobox-open修飾符應用於包裝器時顯示下拉列表
combobox-primary顏色項目的主要主題顏色突出顯示
combobox-secondary顏色項目的次要主題顏色突出顯示
combobox-accent顏色項目的強調主題顏色突出顯示
combobox-info顏色訊息語意顏色高亮
combobox-success顏色成功語意色彩高亮
combobox-warning顏色警告語意顏色突出顯示
combobox-error顏色錯誤語意顏色突出顯示

基本用法

inputcombobox-list 包裝在 relative 容器中。將 combobox-open 添加到包裝器以顯示列表 - 透過 JS 或 :focus-within 切換它。

  • React
  • Vue
  • Angular
  • Svelte
1
2
3
4
5
6
7
8
9
<div class="relative w-64 combobox-open">
  <input type="text" class="input w-full" placeholder="Search or select...">
  <ul class="combobox-list">
    <li class="combobox-item">React</li>
    <li class="combobox-item combobox-item-active">Vue</li>
    <li class="combobox-item">Angular</li>
    <li class="combobox-item">Svelte</li>
  </ul>
</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import { useCombobox } from 'frutjam/react'

const frameworks = ['React', 'Vue', 'Angular', 'Svelte']

export default function ComboboxDemo() {
  const combo = useCombobox({ items: frameworks })
  return (
    <div {...combo.containerProps} className="relative w-64">
      <input {...combo.inputProps} className="input w-full" placeholder="Search or select..." />
      <ul className="combobox-list" role="listbox">
        {combo.filtered.map((item, i) => (
          <li key={item} {...combo.optionProps(item, i)} className="combobox-item">{item}</li>
        ))}
      </ul>
    </div>
  )
}

焦點打開

當輸入獲得焦點時,在包裝器上使用 focus-within:combobox-open 開啟清單 - 無需 JavaScript。

  • React
  • Vue
  • Angular
  • Svelte
html
1
2
3
4
5
6
7
8
9
<div class="relative w-64 focus-within:combobox-open">
  <input type="text" class="input w-full" placeholder="Focus to open...">
  <ul class="combobox-list">
    <li class="combobox-item">React</li>
    <li class="combobox-item">Vue</li>
    <li class="combobox-item">Angular</li>
    <li class="combobox-item">Svelte</li>
  </ul>
</div>

尺寸

在輸入欄位上使用 input-sminput-lg 等。下拉式選單會自然適應。

  • Banana
  • Mango
  • Papaya
  • Banana
  • Mango
  • Papaya
html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<div class="relative w-64 combobox-open">
  <input type="text" class="input input-sm w-full" placeholder="Small">
  <ul class="combobox-list">
    <li class="combobox-item">Banana</li>
    <li class="combobox-item combobox-item-active">Mango</li>
    <li class="combobox-item">Papaya</li>
  </ul>
</div>
<div class="relative w-64 combobox-open">
  <input type="text" class="input input-lg w-full" placeholder="Large">
  <ul class="combobox-list">
    <li class="combobox-item">Banana</li>
    <li class="combobox-item combobox-item-active">Mango</li>
    <li class="combobox-item">Papaya</li>
  </ul>
</div>

顏色

在欄位顏色的輸入上使用 input-primary 等。將符合的 combobox-primary 新增到包裝器中,​​以對活動項目反白進行著色。

  • React
  • Vue
  • Angular
  • React
  • Vue
  • Angular
html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<div class="relative w-64 combobox-open combobox-primary">
  <input type="text" class="input input-primary w-full" placeholder="Primary">
  <ul class="combobox-list">
    <li class="combobox-item">React</li>
    <li class="combobox-item combobox-item-active">Vue</li>
    <li class="combobox-item">Angular</li>
  </ul>
</div>
<div class="relative w-64 combobox-open combobox-error">
  <input type="text" class="input input-error w-full" placeholder="Error">
  <ul class="combobox-list">
    <li class="combobox-item">React</li>
    <li class="combobox-item combobox-item-active">Vue</li>
    <li class="combobox-item">Angular</li>
  </ul>
</div>

殘障人士

html
1
2
3
<div class="relative w-64">
  <input type="text" class="input w-full" placeholder="Disabled" disabled>
</div>

帶按鈕

使用 join 撰寫以附加搜尋圖示或觸發按鈕。

🔍
  • React
  • Vue
  • Angular
  • Svelte
html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<div class="relative w-64 combobox-open">
  <div class="join w-full">
    <span class="join-item btn btn-soft">🔍</span>
    <input type="text" class="input join-item" placeholder="Search...">
  </div>
  <ul class="combobox-list">
    <li class="combobox-item">React</li>
    <li class="combobox-item combobox-item-active">Vue</li>
    <li class="combobox-item">Angular</li>
    <li class="combobox-item">Svelte</li>
  </ul>
</div>

作為連結或按鈕的項目

combobox-item 適用於任何元素 -

  • html
    1
    2
    3
    4
    5
    6
    7
    8
    <div class="relative w-64 combobox-open">
      <input type="text" class="input w-full" placeholder="Search pages...">
      <ul class="combobox-list">
        <a href="#" class="combobox-item">Home</a>
        <a href="#" class="combobox-item combobox-item-active">About</a>
        <button class="combobox-item">Contact</button>
      </ul>
    </div>
    

    JS 和 React 助手

    使用 frutjam/js 中的 createComboboxfrutjam/eact 中的 useCombobox 來獲得過濾、鍵盤導航(↑ ↓ 輸入 Escape)以及開箱即用的完整 aria-* 接線。監聽 fj:select 事件來處理選擇。

    • React
    • Vue
    • Angular
    • Svelte
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <div class="relative w-64" id="js-combobox">
      <input type="text" class="input w-full" placeholder="Search frameworks...">
      <ul class="combobox-list">
        <li class="combobox-option" data-value="react">React</li>
        <li class="combobox-option" data-value="vue">Vue</li>
        <li class="combobox-option" data-value="angular">Angular</li>
        <li class="combobox-option" data-value="svelte">Svelte</li>
      </ul>
    </div>
    <script type="module">
      import { createCombobox } from 'frutjam/js'
      const combo = createCombobox(document.getElementById('js-combobox'))
      document.getElementById('js-combobox').addEventListener('fj:select', (e) => {
        console.log('Selected:', e.detail.value)
      })
    </script>
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import { useCombobox } from 'frutjam/react'
    
    const frameworks = [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
    ]
    
    export default function ComboboxDemo() {
      const combo = useCombobox({ items: frameworks })
      return (
        <div {...combo.containerProps} className="relative w-64">
          <input {...combo.inputProps} className="input w-full" placeholder="Search frameworks..." />
          <ul {...combo.listboxProps} className="combobox-list">
            {combo.filtered.map((item, i) => (
              <li key={item.value} {...combo.optionProps(item, i)}>{item.label}</li>
            ))}
          </ul>
        </div>
      )
    }