選單

選單是你的應用程式基礎的可協助自動完成和命令面板,完整支援鍵盤瀏覽。

首先,透過 npm 安裝 Headless UI

npm install @headlessui/react

組合方塊是使用 ComboboxComboboxInputComboboxButtonComboboxOptionsComboboxOption 元件建立的。

您完全控制您過濾結果的方式,可能是透過一個模糊搜尋函式庫在用戶端過濾,或透過建立伺服器端要求到 API 中過濾。為了示範目的,我們會讓這個範例的邏輯保持簡單。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
      <ComboboxOptions anchor="bottom" className="border empty:invisible">
        {filteredPeople.map((person) => (
          <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100">
            {person.name}
          </ComboboxOption>
        ))}
      </ComboboxOptions>
    </Combobox>
  )
}

Headless UI 追蹤每個元件的很多狀態,例如目前選取哪個組合方塊選項、快顯視窗是否開啟或關閉、或目前使用鍵盤聚焦在選單中的哪個項目。

但由於元件是沒有頭的且完全沒有樣式,在您自己提供每個狀態您想要的樣式之前,您在使用者介面中看不到這些資訊。

要設定 Headless UI 元件不同狀態樣式的最簡單的方式,是使用每個元件公開的 data-* 屬性。

例如,ComboboxOption 元件公開 data-focus 屬性告訴您選項目前是否透過滑鼠或鍵盤聚焦,以及 data-selected 屬性告訴您該選項是否符合 Combobox 目前的 value

<!-- Rendered `ComboboxOptions` -->
<div data-open>
  <div>Wade Cooper</div>
  <div data-focus data-selected>Arlene Mccoy</div>
  <div>Devon Webb</div>
</div>

使用 CSS 屬性選擇器 根據這些資料屬性的存在有條件地套用樣式。如果您使用 Tailwind CSS,資料屬性修改器 會讓這變得容易許多

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { CheckIcon } from '@heroicons/react/20/solid'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
      <ComboboxOptions anchor="bottom" className="border empty:invisible">
        {filteredPeople.map((person) => (
<ComboboxOption key={person.id} value={person} className="group flex gap-2 bg-white data-[focus]:bg-blue-100">
<CheckIcon className="invisible size-5 group-data-[selected]:visible" />
{person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

請見 元件 API 來取得所有可用資料屬性的清單。

每個元件也透過 渲染道具 公開其目前狀態的資訊,您可以用它有條件地套用不同的樣式或渲染不同的內容。

例如,ComboboxOption 元件公開 focus 狀態,告訴您選項目前是否透過滑鼠或鍵盤聚焦,以及一個 selected 狀態,告訴您該選項是否符合 Combobox 目前的 value

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { CheckIcon } from '@heroicons/react/20/solid'
import clsx from 'clsx'
import { Fragment, useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
      <ComboboxOptions anchor="bottom" className="border empty:invisible">
        {filteredPeople.map((person) => (
<ComboboxOption as={Fragment} key={person.id} value={person} className="data-[focus]:bg-blue-100">
{({ focus, selected }) => (
<div className={clsx('group flex gap-2', focus && 'bg-blue-100')}>
{selected && <CheckIcon className="size-5" />}
{person.name}
</div>
)}
</ComboboxOption>
))} </ComboboxOptions> </Combobox> ) }

請見 元件 API 來取得所有可用渲染道具的清單。

Field 元件包裹 LabelCombobox,使用自動產生的 ID 自動將它們關聯起來

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions, Field, Label } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
<Field>
<Label>Assignee:</Label>
<Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}> <ComboboxInput displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox>
</Field>
) }

Field 元件中使用 Description 元件,使用 aria-describedby 屬性將其自動與 Combobox 相關聯

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions, Description, Field, Label } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
<Field>
<Label>Assignee:</Label>
<Description>This person will have full access to this project.</Description>
<Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}> <ComboboxInput displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox>
</Field>
) }

disabled 屬性新增至 Field 元件,以停用 Combobox 及其關聯的 LabelDescription

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions, Field, Label } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
<Field disabled>
<Label>Assignee:</Label> <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}> <ComboboxInput displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> </Field> ) }

您也可以在 Field 外部停用下拉式選單,方法是將 disabled 屬性直接新增至 Combobox 本身。

使用 disabled 屬性停用 ComboboxOption,並防止選取它

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds', available: true },
  { id: 2, name: 'Kenton Towne', available: true },
  { id: 3, name: 'Therese Wunsch', available: true },
{ id: 4, name: 'Benedict Kessler', available: false },
{ id: 5, name: 'Katelyn Rohan', available: true }, ] function Example() { const [selectedPerson, setSelectedPerson] = useState(people[0]) const [query, setQuery] = useState('') const filteredPeople = query === '' ? people : people.filter((person) => { return person.name.toLowerCase().includes(query.toLowerCase()) }) return ( <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}> <ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person}
disabled={!person.available}
className="data-[focus]:bg-blue-100 data-[disabled]:opacity-50"
>
{person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

您可以根據 query 值包含動態 ComboboxOption,允許使用者輸入清單中不存在的自訂值。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
      <ComboboxOptions anchor="bottom" className="border empty:invisible">
{query.length > 0 && (
<ComboboxOption value={{ id: null, name: query }} className="data-[focus]:bg-blue-100">
Create <span className="font-bold">"{query}"</span>
</ComboboxOption>
)}
{filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

如果您新增 name 屬性至您的 Combobox,將會產生隱藏的 input 元素,並與下拉式選單狀態保持同步。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <form action="/projects/1/assignee" method="post">
<Combobox name="assignee" value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
<ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> <button>Submit</button> </form> ) }

這使您可以在原生 HTML <form> 內使用下拉式選單,並進行傳統的表單提交,就像您的下拉式選單是原生 HTML 表單控制項一樣。

基本值(例如字串)將產生包含該值的單一隱藏式輸入,但複雜值(例如物件)會使用中括號表示法針對名稱編碼成多個輸入

<!-- Rendered hidden inputs -->
<input type="hidden" name="assignee[id]" value="1" />
<input type="hidden" name="assignee[name]" value="Durward Reynolds" />

如果你省略 value 道具,Headless UI 會內部追蹤其狀態,允許你使用它作為一個 非受控元件

在非受控時,使用 defaultValue 道具以提供初始值給 Combobox

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <form action="/projects/1/assignee" method="post">
<Combobox name="assignee" defaultValue={people[0]} onClose={() => setQuery('')}>
<ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> <button>Submit</button> </form> ) }

這可以在使用結合框時簡化你的程式碼 使用 HTML 表單 或使用透過 FormData 收集其狀態的表單 API,而不是使用 React 狀態來追蹤它。

如果你需要執行任何副作用,你提供的任何 onChange 道具仍會在元件的值變動時被呼叫,但你不必使用它自己追蹤元件狀態。

加入 anchor 道具到 ComboboxOptions 以讓下拉式選單自動相對於 ComboboxInput 定位

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
<ComboboxOptions anchor="bottom start" className="border empty:invisible">
{filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

使用值 toprightbottomleft 來讓下拉式選單沿著對應邊緣置中,或將它與 startend 結合使用以將下拉式選單對齊到特定角落,例如 top startbottom end

若要控制輸入與下拉式選單之間的間隙,請使用 --anchor-gap CSS 變數

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
<ComboboxOptions
anchor="bottom start" className="border [--anchor-gap:4px] empty:invisible sm:[--anchor-gap:8px]" > {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

此外,你可以使用 --anchor-offset 控制下拉式選單應該從其原始位置輕推的距離,以及 --anchor-padding 控制下拉式選單和視窗之間應該存在的最小空間。

anchor 道具也支援一個物件 API,允許你使用 JavaScript 控制 gapoffsetpadding

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
<ComboboxOptions anchor={{ to: 'bottom start', gap: '4px' }} className="border empty:invisible">
{filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

請參閱 ComboboxOptions API 以取得更多關於這些選項的資訊。

ComboboxOptions 下拉式選單預設沒有設定寬度,但你可以使用 CSS 新增一個

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
<ComboboxOptions anchor="bottom" className="w-52 border empty:invisible">
{filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

如果你想要下拉式選單寬度與 ComboboxInputComboboxButton 寬度匹配,請使用 --input-width--button-width CSS 變數,它們在 ComboboxOptions 元素上公開

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
<ComboboxOptions anchor="bottom" className="w-[var(--input-width)] border empty:invisible">
{filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

若要動畫化開合組合框面板,請加入 transition 道具到 ComboboxOptions 元件,然後使用 CSS 來設定轉場的不同階段

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
      <ComboboxOptions
        anchor="bottom"
transition
className="origin-top border transition duration-200 ease-out empty:invisible data-[closed]:scale-95 data-[closed]:opacity-0"
>
{filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

在內部,transition 道具是以與 Transition 元件完全相同的方式實作。請參閱 轉場文件 以進一步了解。

Headless UI 搭配 React 生態系中的其他動畫函式庫,例如 Framer MotionReact Spring,效果也很好。您只需要向這些函式庫公開一些狀態。

例如,若要使用 Framer Motion 對組合方塊進行動畫處理,請將 static 屬性新增到 ComboboxOptions 元件,然後根據 open 渲染屬性來有條件地呈現。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { AnimatePresence, motion } from 'framer-motion'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson}>
{({ open }) => (
<> <ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <AnimatePresence>
{open && (
<ComboboxOptions
static
as={motion.div} initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.95 }} anchor="bottom" className="origin-top border empty:invisible" onAnimationComplete={() => setQuery('')} >
{filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions>
)}
</AnimatePresence> </>
)}
</Combobox> ) }

與僅允許您提供字串作為值的原生 HTML 表單控制項不同,Headless UI 也支援繫結複雜物件。

繫結物件時,請務必在 ComboboxInput 上設定 displayValue,以便可以在輸入中呈現已選取選項的字串表示。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
{ id: 1, name: 'Durward Reynolds' },
{ id: 2, name: 'Kenton Towne' },
{ id: 3, name: 'Therese Wunsch' },
{ id: 4, name: 'Benedict Kessler' },
{ id: 5, name: 'Katelyn Rohan' },
]
function Example() { const [selectedPerson, setSelectedPerson] = useState(people[0]) const [query, setQuery] = useState('') const filteredPeople = query === '' ? people : people.filter((person) => { return person.name.toLowerCase().includes(query.toLowerCase()) }) return (
<Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
<ComboboxInput aria-label="Assignee"
displayValue={(person) => person?.name}
onChange={(event) => setQuery(event.target.value)} />
<ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100">
{person.name}
</ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

將物件繫結為值時, важно 從 Comboboxvalue 及對應的 ComboboxOption,務必使用同一個物件的 相同執行個體,否則這些執行個體將無法相等並導致組合方塊行為不正確。

若要簡化使用同一個物件的不同執行個體,您可以使用 by 屬性來根據特定欄位比較物件,而不是比較物件身分。

當您將物件傳遞給 value 屬性時,by 預設是 id(存在時),但您可以設定為您想要的欄位

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const departments = [
  { name: 'Marketing', contact: 'Durward Reynolds' },
  { name: 'HR', contact: 'Kenton Towne' },
  { name: 'Sales', contact: 'Therese Wunsch' },
  { name: 'Finance', contact: 'Benedict Kessler' },
  { name: 'Customer service', contact: 'Katelyn Rohan' },
]

function DepartmentPicker({ selectedDepartment, onChange }) {
const [query, setQuery] = useState('') const filteredDepartments = query === '' ? departments : departments.filter((department) => { return department.name.toLowerCase().includes(query.toLowerCase()) }) return (
<Combobox value={selectedDepartment} by="name" onChange={onChange} onClose={() => setQuery('')}>
<ComboboxInput aria-label="Department" displayValue={(department) => department?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredDepartments.map((department) => ( <ComboboxOption key={department.id} value={department} className="data-[focus]:bg-blue-100"> {department.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

如果希望完全控制比較物件的方式,也可以將您自己的比較函式傳遞給 by 屬性

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const departments = [
  { id: 1, name: 'Marketing', contact: 'Durward Reynolds' },
  { id: 2, name: 'HR', contact: 'Kenton Towne' },
  { id: 3, name: 'Sales', contact: 'Therese Wunsch' },
  { id: 4, name: 'Finance', contact: 'Benedict Kessler' },
  { id: 5, name: 'Customer service', contact: 'Katelyn Rohan' },
]

function compareDepartments(a, b) {
return a.name.toLowerCase() === b.name.toLowerCase()
}
function DepartmentPicker({ selectedDepartment, onChange }) { const [query, setQuery] = useState('') const filteredDepartments = query === '' ? departments : departments.filter((department) => { return department.name.toLowerCase().includes(query.toLowerCase()) }) return (
<Combobox value={selectedDepartment} by={compareDepartments} onChange={onChange} onClose={() => setQuery('')}>
<ComboboxInput aria-label="Department" displayValue={(department) => department?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredDepartments.map((department) => ( <ComboboxOption key={department.id} value={department} className="data-[focus]:bg-blue-100"> {department.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

儘管 將物件繫結為值 很常見,但您也可以提供簡單的字串值。

這樣做時,您可以省略 ComboboxInputdisplayValue 屬性。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = ['Durward Reynolds', 'Kenton Towne', 'Therese Wunsch', 'Benedict Kessler', 'Katelyn Rohan']
function Example() { const [selectedPerson, setSelectedPerson] = useState(people[0]) const [query, setQuery] = useState('') const filteredPeople = query === '' ? people : people.filter((person) => { return person.toLowerCase().includes(query.toLowerCase()) }) return ( <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}> <ComboboxInput aria-label="Assignee" onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => (
<ComboboxOption key={person} value={person} className="data-[focus]:bg-blue-100">
{person}
</ComboboxOption>
))} </ComboboxOptions> </Combobox> ) }

若要允許在組合方塊中選取多個值,請使用 multiple 屬性,並將陣列傳遞給 value,而不是單一選項。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
const [selectedPeople, setSelectedPeople] = useState([people[0], people[1]])
const [query, setQuery] = useState('') const filteredPeople = query === '' ? people : people.filter((person) => { return person.name.toLowerCase().includes(query.toLowerCase()) }) return (
<Combobox multiple value={selectedPeople} onChange={setSelectedPeople} onClose={() => setQuery('')}>
{selectedPeople.length > 0 && ( <ul> {selectedPeople.map((person) => ( <li key={person.id}>{person.name}</li> ))} </ul> )} <ComboboxInput aria-label="Assignees" onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

每次新增或移除選項時,您的 onChange 處理常式會呼叫陣列,陣列中包含所有已選取的選項。

使用 立即 屬性以在組合方塊輸入獲得焦點時立即開啟組合方塊選項。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
<Combobox immediate value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
<ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

預設情況下,組合方塊 及其子元件各呈現適合該元件的預設元素。

例如,組合方塊輸入 呈現 輸入組合方塊按鈕 呈現 按鈕組合方塊選項 呈現 div,而 組合方塊選項 呈現 div。相反,組合方塊 不呈現元素,而是直接呈現其子元素。

使用 作為 屬性以將元件呈現為不同元素或您自己的自訂元件,確保您的自訂元件 將參考傳送出去,以便 Headless UI 就能正確建立連結。

import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { forwardRef, useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

let MyCustomButton = forwardRef(function (props, ref) {
return <button className="..." ref={ref} {...props} />
})
function Example() { const [selectedPerson, setSelectedPerson] = useState(people[0]) const [query, setQuery] = useState('') const filteredPeople = query === '' ? people : people.filter((person) => { return person.name.toLowerCase().includes(query.toLowerCase()) }) return (
<Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
<ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxButton as={MyCustomButton}>Open</ComboboxButton>
<ComboboxOptions as="ul" anchor="bottom" className="border empty:invisible">
{filteredPeople.map((person) => (
<ComboboxOption as="li" key={person.id} value={person} className="data-[focus]:bg-blue-100">
{person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

若要讓元素直接呈現其子元素而沒有包裝元素,請使用 片段

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { Fragment, useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
as={Fragment}
aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} >
<input /> </ComboboxInput> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions> </Combobox> ) }

根據您所建立的內容,有時將 組合方塊選項 以外的額外資訊呈現為主動選項是有意義的。例如,在命令面板中預覽主動選項。在這些情況下,您可以讀取 主動選項 呈現屬性引數來存取此資訊。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
{({ activeOption }) => (
<> <ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="border empty:invisible"> {filteredPeople.map((person) => ( <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100"> {person.name} </ComboboxOption> ))} </ComboboxOptions>
{activeOption && <div>The currently focused user is: {activeOption.name}</div>}
</> )} </Combobox> ) }

主動選項 將成為目前有焦點 組合方塊選項

預設情況下,組合方塊 會將其所有選項呈現到 DOM 中。雖然這是一個良好的預設設定,但在選項數量非常多時,這可能會導致效能問題。針對這些情況,我們提供了虛擬捲動 API。

若要啟用虛擬捲動,請透過 虛擬.選項 屬性提供選項清單給 組合方塊,並提供 組合方塊選項 呈現屬性,作為每個選項的範本。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
  // +1000 more people
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox
      value={selectedPerson}
virtual={{ options: filteredPeople }}
onChange={setSelectedPerson} onClose={() => setQuery('')} >
<ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="w-[var(--input-width)] border empty:invisible">
{({ option: person }) => (
<ComboboxOption value={person} className="data-[focus]:bg-blue-100">
{person.name}
</ComboboxOption>
)}
</ComboboxOptions> </Combobox> ) }

若要指定給定的選項是否已停用,請提供回呼至 虛擬.停用 屬性。

import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds', available: true },
  { id: 2, name: 'Kenton Towne', available: true },
  { id: 3, name: 'Therese Wunsch', available: true },
{ id: 4, name: 'Benedict Kessler', available: false },
{ id: 5, name: 'Katelyn Rohan', available: true }, // +1000 more people ] function Example() { const [selectedPerson, setSelectedPerson] = useState(people[0]) const [query, setQuery] = useState('') const filteredPeople = query === '' ? people : people.filter((person) => { return person.name.toLowerCase().includes(query.toLowerCase()) }) return ( <Combobox value={selectedPerson} virtual={{ options: filteredPeople,
disabled: (person) => !person.available,
}}
onChange={setSelectedPerson} onClose={() => setQuery('')} >
<ComboboxInput aria-label="Assignee" displayValue={(person) => person?.name} onChange={(event) => setQuery(event.target.value)} /> <ComboboxOptions anchor="bottom" className="w-[var(--input-width)] border empty:invisible"> {({ option: person }) => (
<ComboboxOption value={person} className="data-[focus]:bg-blue-100 data-[disabled]:opacity-50">
{person.name} </ComboboxOption> )} </ComboboxOptions> </Combobox> ) }

指令說明

向下箭頭向上箭頭ComboboxInput 獲得焦點時

開啟下拉式選單並將焦點移至選取的項目

Enter空白鍵向下箭頭向上箭頭ComboboxButton 獲得焦點時

開啟下拉式選單,將焦點移至輸入並選取選取的項目

Esc當下拉式選單開啟時

關閉下拉式選單並恢復在輸入欄位中的選取項目

向下箭頭向上箭頭當下拉式選單開啟時

將焦點移至上一個/下一個已啟用的項目

首頁PgUp當下拉式選單開啟時

將焦點移至第一個已啟用的項目

尾頁PgDn當下拉式選單開啟時

將焦點移至最後一個已啟用的項目

Enter當下拉式選單開啟時

選取目前項目

Enter當下拉式選單關閉且在表單中時

提交表單

Tab當組合方塊開啟時

選取當前焦點的項目並關閉組合方塊

A–Za–z當組合方塊開啟時

呼叫 onChange,可以過濾清單

組合方塊主元件。

prop預設值說明
as片段
字串 | 元件

組配方塊應該呈現地或元件。解組合方塊呈現在這個設定的

disabledfalse
布林

使用這個設定來停用整個組合方塊元件 & 相關的子元件。

value
T

選取的值。

defaultValue
T

當使用為非受控元件時的預設值。

by
keyof T | ((a: T, z: T) => 布林)

使用這個設定來比較特定欄位的物件,或是傳遞你自己的比較函式來完全控制比較物件的方式。

當你傳遞物件給 value prop 時,by 預設為id(如果存在的話)。

onChange
(value: T) => 無

當選取新的選項時呼叫的函式。

onClose
() => 無

當下拉式選單關閉時呼叫的函式。

multiplefalse
布林

是否可以選取多個選項

name
字串

用於組合方塊在表單內使用

form
字串

屬於組合方塊的表單 ID

如果提供 name 但沒有 form組合方塊會將其狀態加入最近父層的 form 元素。

immediatefalse
布林

組合方塊輸入被設定焦點時,組合方塊是否應該立刻開啟選項。

virtualnull
物件

設定虛擬捲動。

virtual.options
陣列

在虛擬捲動模式時顯示的選項集合。

virtual.disablednull
(value: T) => 布林

在虛擬捲動模式時用來決定給定選項是否已停用的回呼。

資料屬性呈現 Prop說明
value

T

選取的值。

data-openopen

布林

是否組合方塊已開啟.

activeOption

T | null

有焦點的選項,或 null(如果沒有焦點的選項)。

data-disableddisabled

布林

是否組合方塊已停用。

activeIndex

數字 | null

聚焦的選項索引,如果沒有焦點則為 null

Combobox 的輸入內容。

prop預設值說明
as輸入
字串 | 元件

組配方塊應該呈現地或元件。解combobox 輸入內容呈現在這個設定的

顯示值
(項目: T) => 字串

value 的字串表示形式。

onChange
(事件: Event) => void

在輸入值變更時要呼叫的函式。

自動對焦false
布林

是否combobox 輸入內容首次呈現時應收到焦點。

資料屬性呈現 Prop說明
data-openopen

布林

是否組合方塊已開啟.

data-disableddisabled

布林

是否組合方塊已停用。

data-焦點焦點

布林

是否combobox 輸入內容已聚焦。

data-懸停懸停

布林

是否combobox 輸入內容已懸停。

data-自動對焦自動對焦

布林

autoFocus 屬性是否設為 true

Combobox 的按鈕。

prop預設值說明
as按鈕
字串 | 元件

組配方塊應該呈現地或元件。解combobox 按鈕呈現在這個設定的

自動對焦false
布林

是否combobox 按鈕首次呈現時應收到焦點。

資料屬性呈現 Prop說明
value

T

選取的值。

data-openopen

布林

是否組合方塊已開啟.

data-disableddisabled

布林

是否combobox 按鈕已停用。

data-焦點焦點

布林

是否combobox 按鈕已聚焦。

data-懸停懸停

布林

是否combobox 按鈕已懸停。

data-活動活動

布林

是否combobox 按鈕處於活動或按下的狀態。

直接包覆自訂 Combobox 中選項清單的元件。

prop預設值說明
asdiv
字串 | 元件

組配方塊應該呈現地或元件。解combobox 選項呈現在這個設定的

過渡false
布林

元素是否應呈現過渡屬性,例如 data-closed data-enterdata-leave

定位點
物件

設定下拉選單固定在輸入內容的方式。

anchor.to底部
字串

放置combobox 選項相對於觸發器。

使用值 toprightbottomleft combobox 選項置中於適當的邊緣,或將其與 startend 結合以將combobox 選項對齊到特定角落,例如 top startbottom end

anchor.gap0
數字 | 字串

之間的間距combobox 輸入內容combobox 選項.

也可以使用 --anchor-gap CSS 變數來控制。

anchor.offset0
數字 | 字串

距離combobox 選項應從其原始位置略微調整。

也可以使用 --anchor-offset CSS 變數來控制。

anchor.padding0
數字 | 字串

之間的最小空間combobox 選項和視窗。

也可以使用 --anchor-padding CSS 變數來控制。

靜態false
布林

元素是否應略過內部管理的開啟/關閉狀態。

解除安裝true
布林

元素是否應根據開啟/關閉狀態解除安裝或隱藏。

入口false
布林

元素是否應在入口中呈現。

當設定 anchor 屬性時自動設為 true

模式true
布林

是否啟用輔助功能,例如捲動鎖定、焦點捕捉,以及使其他元素 惰性.

資料屬性呈現 Prop說明
data-openopen

布林

是否組合方塊已開啟.

用於包裹在 Combobox 中的每個項目。

prop預設值說明
asdiv
字串 | 元件

組配方塊應該呈現地或元件。解combobox 選項呈現在這個設定的

value
T

選項值。

disabledfalse
布林

是否combobox 選項已禁用用於鍵盤導覽和 ARIA 用途.

順序
數字

選項在選項清單中的順序,用於效能改善。

使用虛擬捲動時無關緊要。

資料屬性呈現 Prop說明
data-已選取已選取

布林

是否combobox 選項已被選取。

data-disableddisabled

布林

是否combobox 選項已停用。

data-焦點焦點

布林

是否combobox 選項已聚焦。

如果您有興趣使用預先設計的 Tailwind CSS Combobox 組件範例使用 Headless UI,請查看 Tailwind UI — 由我們建立的精選美觀設計和精心製作的組件。

對於像這樣開源專案,這是支持我們工作的絕佳方式,並使我們能夠改善這些開源專案與持續維護。