コンボボックス
コンボボックスは、アクセシビリティの高いオートコンプリートとアプリケーションのコマンドパレットの基盤であり、キーボードナビゲーションを強力にサポートしています。
開始するには、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 をご覧ください。これは、私たちによって構築された、美しくデザインされ、専門的に作られたコンポーネントのコレクションです。
これは、このようなオープンソースプロジェクトへの私たちの活動を支援する素晴らしい方法であり、それらを改善し、維持することを可能にします。