Combobox with TagsInput
Render a Combobox with tags that can be removed.
Render a Combobox with tags that can be removed.
import { Combobox, createListCollection } from '@ark-ui/react/combobox'
import { TagsInput } from '@ark-ui/react/tags-input'
import { matchSorter } from 'match-sorter'
import { useId, useMemo, useRef, useState } from 'react'
import { data } from './data'
export const Example = () => {
const [items, setItems] = useState(data)
const [value, setValue] = useState<string[]>([])
const [inputValue, setInputValue] = useState('')
const contentRef = useRef<HTMLDivElement>(null)
const ids = {
root: useId(),
input: useId(),
control: useId(),
}
const collection = useMemo(
() =>
createListCollection({
items,
}),
[items],
)
return (
<Combobox.Root
ids={ids}
allowCustomValue
multiple
selectionBehavior="clear"
collection={collection}
value={value}
onValueChange={(details) => {
setValue(details.value)
setItems((curr) => curr.filter((item) => !details.value.includes(item.value)))
contentRef.current?.scrollTo(0, 0)
}}
onOpenChange={() => setItems(data.filter((item) => !value.includes(item.value)))}
onInputValueChange={({ inputValue }) => {
const result = matchSorter(data, inputValue, {
keys: ['label'],
baseSort: (a, b) => (a.index < b.index ? -1 : 1),
})
setItems(result)
}}
asChild
>
<TagsInput.Root
ids={ids}
value={value}
inputValue={inputValue}
editable={false}
addOnPaste={false}
onValueChange={(details) => setValue(details.value)}
onInputValueChange={(details) => setInputValue(details.inputValue)}
>
<Combobox.Label>Country</Combobox.Label>
<TagsInput.Context>
{(tagsInput) => (
<Combobox.Control asChild>
<TagsInput.Control>
{tagsInput.value.map((value, index) => (
<TagsInput.Item key={index} index={index} value={value}>
<TagsInput.ItemPreview>
<TagsInput.ItemText>
{data.find((item) => item.value === value)?.label ?? value}
</TagsInput.ItemText>
<TagsInput.ItemDeleteTrigger>Delete</TagsInput.ItemDeleteTrigger>
</TagsInput.ItemPreview>
<TagsInput.ItemInput />
</TagsInput.Item>
))}
<Combobox.Input
asChild
placeholder="Add Country"
onKeyDown={(event) => {
if (event.key === 'Enter' && items.length === 0) {
tagsInput.addValue(inputValue)
}
}}
>
<TagsInput.Input />
</Combobox.Input>
</TagsInput.Control>
</Combobox.Control>
)}
</TagsInput.Context>
<Combobox.Positioner>
{items.length > 0 && (
<Combobox.Content ref={contentRef}>
{items.map((item) => (
<Combobox.Item key={item.value} item={item}>
{item.label}
</Combobox.Item>
))}
</Combobox.Content>
)}
</Combobox.Positioner>
</TagsInput.Root>
</Combobox.Root>
)
}