コンボボックス
コンボボックスは、アクセシビリティの高いオートコンプリートとアプリケーションのコマンドパレットの基盤であり、キーボードナビゲーションを強力にサポートしています。
開始するには、npm 経由で Headless UI をインストールします。
npm install @headlessui/reactコンボボックスは、Combobox、ComboboxInput、ComboboxButton、ComboboxOptions、ComboboxOption コンポーネントを使用して構築されています。
結果のフィルタリング方法は完全にユーザーが制御できます。クライアントサイドでファジー検索ライブラリを使用するか、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 は、各コンポーネントに関する多くの状態(現在選択されているコンボボックスオプション、ポップオーバーが開いているか閉じているか、キーボードで現在フォーカスされているメニューのアイテムなど)を追跡します。
しかし、コンポーネントはヘッドレスで、すぐに使用できる状態では完全にスタイルが適用されていないため、ユーザー自身が各状態に望ましいスタイルを適用するまで、UIではこの情報は表示されません。
Headless UI コンポーネントのさまざまな状態をスタイリングする最も簡単な方法は、各コンポーネントが公開するdata-*属性を使用することです。
たとえば、ComboboxOptionコンポーネントは、マウスまたはキーボードでオプションが現在フォーカスされているかどうかを示すdata-focus属性と、そのオプションがComboboxの現在のvalueと一致するかどうかを示すdata-selected属性を公開します。
<!-- 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状態と、そのオプションがComboboxの現在のvalueと一致するかどうかを示すselected状態を公開します。
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を参照してください。
生成されたIDを使用して自動的に関連付けるには、LabelとComboboxをFieldコンポーネントでラップします。
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>  )
}
aria-describedby属性を使用してComboboxと自動的に関連付けるには、Field内にDescriptionコンポーネントを使用します。
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>  )
}
Comboboxとその関連するLabelとDescriptionを無効化するには、Fieldコンポーネントにdisabledプロップを追加します。
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>
  )
}
Combobox自体にdisabledプロップを直接追加することで、`Field`の外でもコンボボックスを無効化することもできます。
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>
  )
}
Comboboxにnameプロップを追加すると、非表示の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プロップは引き続き呼び出されます(副作用を実行する必要がある場合)。ただし、コンポーネントの状態を自分で追跡するために使用する必要はありません。
ComboboxInputを基準にドロップダウンを自動的に配置するには、ComboboxOptionsにanchorプロップを追加します。
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>
  )
}
top、right、bottom、またはleftの値を使用して、適切なエッジに沿ってドロップダウンを中心揃えするか、startまたはendと組み合わせて、top startまたはbottom 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プロップは、JavaScriptを使用してgap、offset、paddingの値を制御できるオブジェクト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={{ 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>
  )
}
ドロップダウンの幅をComboboxInputまたはComboboxButtonの幅と一致させるには、ComboboxOptions要素で公開される--input-widthと--button-widthの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-[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>
  )
}
コンボボックスパネルの開閉をアニメーション化するには、ComboboxOptionsコンポーネントにtransitionプロップを追加し、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 は、Framer MotionやReact SpringなどのReactエコシステムの他のアニメーションライブラリとも連携します。これらのライブラリに状態を公開するだけです。
例えば、Framer Motion を使用してコンボボックスをアニメーション化するには、ComboboxOptions コンポーネントにstatic プロップを追加し、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>
  )
}
値としてオブジェクトをバインドする場合は、Combobox のvalue と対応する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>
  )
}
値としてオブジェクトをバインドすることは非常に一般的ですが、単純な文字列値を提供することもできます。
この場合、ComboboxInput からdisplayValue プロップを省略できます。
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 ハンドラーが呼び出されます。
immediate プロップを使用して、コンボボックス入力がフォーカスされたときにコンボボックスオプションをすぐに開きます。
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>
  )
}
デフォルトでは、Combobox とそのサブコンポーネントはそれぞれ、そのコンポーネントに適したデフォルトの要素をレンダリングします。
例えば、ComboboxInput はinput を、ComboboxButton はbutton を、ComboboxOptions はdiv を、ComboboxOption はdiv をレンダリングします。対照的に、Combobox は要素をレンダリングしません。代わりに、その子要素を直接レンダリングします。
as プロップを使用して、コンポーネントを異なる要素または独自のカスタムコンポーネントとしてレンダリングします。カスタムコンポーネントがフォワードリファレンスされていることを確認して、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>
  )
}
ラッパー要素なしで子要素を直接レンダリングする要素を指定するには、Fragment を使用します。
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>
  )
}
構築しているものによっては、ComboboxOptions の外部でアクティブなオプションに関する追加情報をレンダリングすることが理にかなう場合があります。例えば、コマンドパレットのコンテキスト内でのアクティブなオプションのプレビューなどです。このような状況では、activeOption レンダリングプロップ引数を読み取って、この情報にアクセスできます。
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>
  )
}
activeOption は、現在フォーカスされているComboboxOption のvalue になります。
デフォルトでは、Combobox はすべてのオプションをDOMにレンダリングします。これは優れたデフォルトですが、非常に多くのオプションが与えられると、パフォーマンスの問題を引き起こす可能性があります。このような状況のために、仮想スクロールAPIを提供しています。
仮想スクロールを有効にするには、virtual.options プロップを介してオプションのリストをCombobox に提供し、各オプションのテンプレートとして機能するレンダリングプロップを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' },
  // +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>
  )
}
特定のオプションが無効かどうかを指定するには、virtual.disabled プロップにコールバックを提供します。
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>
  )
}
| コマンド | 説明 | 
| 下矢印、または上矢印 | コンボボックスを開き、選択した項目にフォーカスします。 | 
| Enter、Space、下矢印、または上矢印 | コンボボックスを開き、入力にフォーカスして選択した項目を選択します。 | 
| Escコンボボックスが開いている場合 | コンボボックスを閉じ、入力フィールドに選択した項目を復元します。 | 
| 下矢印または上矢印コンボボックスが開いている場合 | 無効でない前の/次の項目にフォーカスします。 | 
| HomeまたはPageUpコンボボックスが開いている場合 | 無効でない最初の項目にフォーカスします。 | 
| EndまたはPageDownコンボボックスが開いている場合 | 無効でない最後の項目にフォーカスします。 | 
| Enterコンボボックスが開いている場合 | 現在の項目を選択します。 | 
| Enterコンボボックスが閉じられていてフォーム内にある場合 | フォームを送信します。 | 
| Tabコンボボックスが開いている場合 | 現在フォーカスされている項目を選択し、コンボボックスを閉じます。 | 
| A~Zまたはa~zコンボボックスが開いている場合 | リストをフィルタリングできる | 
| プロップ | デフォルト | 説明 | 
| as | Fragment | 文字列 | コンポーネントコンボボックスがレンダリングされるべき要素またはコンポーネント。comboboxです。 | 
| disabled | false | ブール値これを使用して、コンボボックスコンポーネント全体と関連する子要素を無効にします。 | 
| value | — | T選択された値。 | 
| defaultValue | — | T制御されていないコンポーネントとして使用する場合のデフォルト値。 | 
| by | — | keyof T | ((a: T, z: T) => boolean)特定のフィールドでオブジェクトを比較するためにこれを使用するか、オブジェクトの比較方法を完全に制御するために独自の比較関数を渡します。 オブジェクトを | 
| onChange | — | (value: T) => void新しいオプションが選択されたときに呼び出す関数。 | 
| onClose | — | () => voidドロップダウンが閉じられたときに呼び出す関数。 | 
| multiple | false | ブール値複数のオプションを選択できるかどうか。 | 
| name | — | 文字列フォーム内で使用する場合の名前。combobox内部。 | 
| form | — | 文字列が属するフォームのID。comboboxです。 
 | 
| immediate | false | ブール値コンボボックス入力がフォーカスされたときに、コンボボックスがそのオプションをすぐに開くかどうか。 | 
| virtual | null | オブジェクト仮想スクロールを構成します。 | 
| virtual.options | — | 配列仮想スクロールモードで表示するオプションのコレクション。 | 
| virtual.disabled | null | (value: T) => boolean仮想スクロールモードで特定のオプションが無効かどうかを判断するためのコールバック。 | 
| データ属性 | レンダリングプロップ | 説明 | 
| — | value | 
 選択された値。 | 
| data-open | open | 
 かどうかcomboboxが開いています。 | 
| — | activeOption | 
 フォーカスされているオプション、またはフォーカスされていない場合は | 
| data-disabled | disabled | 
 かどうかcombobox無効化されています。 | 
| — | activeIndex | 
 フォーカスされているオプションのインデックス、またはフォーカスされていない場合は | 
| プロップ | デフォルト | 説明 | 
| as | input | 文字列 | コンポーネントコンボボックスがレンダリングされるべき要素またはコンポーネント。コンボボックス入力です。 | 
| displayValue | — | (item: T) => string
 | 
| onChange | — | (event: Event) => void入力値が変更されたときに呼び出される関数。 | 
| autoFocus | false | ブール値かどうかコンボボックス入力最初にレンダリングされたときにフォーカスを受け取るべきかどうか。 | 
| データ属性 | レンダリングプロップ | 説明 | 
| data-open | open | 
 かどうかcomboboxが開いています。 | 
| data-disabled | disabled | 
 かどうかcombobox無効化されています。 | 
| data-focus | focus | 
 かどうかコンボボックス入力フォーカスされている。 | 
| data-hover | hover | 
 かどうかコンボボックス入力ホバーされている。 | 
| data-autofocus | autofocus | 
 
 | 
| プロップ | デフォルト | 説明 | 
| as | button | 文字列 | コンポーネントコンボボックスがレンダリングされるべき要素またはコンポーネント。コンボボックスボタンです。 | 
| autoFocus | false | ブール値かどうかコンボボックスボタン最初にレンダリングされたときにフォーカスを受け取るべきかどうか。 | 
| データ属性 | レンダリングプロップ | 説明 | 
| — | value | 
 選択された値。 | 
| data-open | open | 
 かどうかcomboboxが開いています。 | 
| data-disabled | disabled | 
 かどうかコンボボックスボタン無効化されています。 | 
| data-focus | focus | 
 かどうかコンボボックスボタンフォーカスされている。 | 
| data-hover | hover | 
 かどうかコンボボックスボタンホバーされている。 | 
| data-active | active | 
 かどうかコンボボックスボタンアクティブまたは押された状態である。 | 
| プロップ | デフォルト | 説明 | 
| as | div | 文字列 | コンポーネントコンボボックスがレンダリングされるべき要素またはコンポーネント。コンボボックスオプションです。 | 
| transition | false | ブール値
 | 
| anchor | — | オブジェクトドロップダウンが入力欄にどのようにアンカーされるかを設定します。 | 
| anchor.to | bottom | 文字列トリガーに対してコンボボックスオプションどこに配置するか。 
 | 
| anchor.gap | 0 | Number | Stringとコンボボックス入力の間隔。コンボボックスオプション. 
 | 
| anchor.offset | 0 | Number | Stringを元の位置からコンボボックスオプションずらすべき距離。 
 | 
| anchor.padding | 0 | Number | Stringとビューポートの間の最小間隔。コンボボックスオプション 
 | 
| static | false | ブール値要素が内部的に管理されている開閉状態を無視するかどうか。 | 
| unmount | true | ブール値開閉状態に基づいて、要素をアンマウントするか、非表示にするかどうか。 | 
| portal | false | ブール値要素をポータルでレンダリングするかどうか。 
 | 
| modal | true | ブール値スクロールロック、フォーカストラップ、他の要素を不活性にするなどのアクセシビリティ機能を有効にするかどうか。  | 
| データ属性 | レンダリングプロップ | 説明 | 
| data-open | open | 
 かどうかcomboboxが開いています。 | 
| プロップ | デフォルト | 説明 | 
| as | div | 文字列 | コンポーネントコンボボックスがレンダリングされるべき要素またはコンポーネント。コンボボックスオプションです。 | 
| value | — | Tオプションの値。 | 
| disabled | false | ブール値かどうかコンボボックスオプション無効化されていますキーボードナビゲーションとARIAの目的で。. | 
| order | — | Numberオプションリストにおけるオプションの順序。パフォーマンス向上に使用されます。 仮想スクロールを使用する場合は関係ありません。 | 
| データ属性 | レンダリングプロップ | 説明 | 
| data-selected | selected | 
 かどうかコンボボックスオプション選択されています。 | 
| data-disabled | disabled | 
 かどうかコンボボックスオプション無効化されています。 | 
| data-focus | focus | 
 かどうかコンボボックスオプションフォーカスされている。 | 
Headless UI を使用した、事前にデザインされた Tailwind CSS コンボボックスコンポーネントの例 に興味がある場合は、Tailwind UI をご覧ください。これは、私たちによって構築された、美しくデザインされ、専門的に作られたコンポーネントのコレクションです。
これは、このようなオープンソースプロジェクトへの私たちの活動を支援する素晴らしい方法であり、それらを改善し、維持することを可能にします。
