Combobox
Combobox
텍스트 입력과 리스트박스를 결합한 다용도 입력 컴포넌트예요. 옵션 목록을 필터링하고 단일 또는 다중 값을 선택할 수 있게 해 줘요.
출처: 문서
본문
사용법 (Usage)
import { Combobox } from "@chakra-ui/react"
<Combobox.Root>
<Combobox.Label />
<Combobox.Control>
<Combobox.Input />
<Combobox.IndicatorGroup>
<Combobox.ClearTrigger />
<Combobox.Trigger />
</Combobox.IndicatorGroup>
</Combobox.Control>
<Combobox.Positioner>
<Combobox.Content>
<Combobox.Empty />
<Combobox.Item />
<Combobox.ItemGroup>
<Combobox.ItemGroupLabel />
<Combobox.Item />
</Combobox.ItemGroup>
</Combobox.Content>
</Combobox.Positioner>
</Combobox.Root>
콤보박스를 설정하려면 다음 훅들을 import해야 해요:
-
useListCollection: 콤보박스에서 list collection을 관리하는 데 사용하며, 목록을 필터링하고 변경하는 유용한 메서드를 제공해요. -
useFilter:Intl.CollatorAPI를 기반으로 콤보박스의 필터링 로직을 제공하는 데 사용해요.
예시 (Examples)
기본 (Basic)
기본 콤보박스는 단일 선택이 가능한 검색 가능한 드롭다운을 제공해요.
크기 (Sizes)
Combobox.Root에 size prop을 전달하면 콤보박스의 크기를 바꿀 수 있어요.
변형 (Variants)
Combobox.Root에 variant prop을 전달하면 콤보박스의 모양을 바꿀 수 있어요.
다중 선택 (Multiple)
Combobox.Root에 multiple prop을 전달하면 다중 선택을 활성화할 수 있어요. 이렇게 하면 사용자가 목록에서 여러 항목을 선택할 수 있어요.
이 값이 설정되면 콤보박스는 항목이 선택될 때마다 항상 입력 값을 지워요.
비동기 로딩 (Async Loading)
사용자가 입력할 때 collection을 비동기로 로드하는 예시예요. API 기반 검색 인터페이스에 완벽해요.
일치 텍스트 강조 (Highlight Matching Text)
Combobox.Item과 Highlight 컴포넌트를 조합해 검색 결과에서 일치하는 텍스트를 강조하는 예시예요.
클릭 시 열기 (Open on Click)
openOnClick prop을 사용하면 사용자가 입력 필드를 클릭할 때 콤보박스가 열리게 할 수 있어요.
커스텀 객체 (Custom Objects)
기본적으로 콤보박스 컬렉션은 label과 value 속성을 가진 객체 배열을 기대해요. 어떤 경우에는 커스텀 객체를 다뤄야 할 수도 있어요.
itemToString과 itemToValue prop을 사용해 커스텀 객체를 필요한 인터페이스에 매핑할 수 있어요.
const items = [
{ country: "United States", code: "US", flag: "🇺🇸" },
{ country: "Canada", code: "CA", flag: "🇨🇦" },
{ country: "Australia", code: "AU", flag: "🇦🇺" },
// ...
]
const { contains } = useFilter({ sensitivity: "base" })
const { collection } = useListCollection({
initialItems: items,
itemToString: (item) => item.country,
itemToValue: (item) => item.code,
filter: contains,
})
최소 문자 수 (Minimum Characters)
openOnChange prop을 사용하면 목록을 필터링하기 전에 필요한 최소 문자 수를 설정할 수 있어요.
<Combobox.Root openOnChange={(e) => e.inputValue.length > 2} />
필드 (Field)
Combobox 컴포넌트를 Field 컴포넌트와 구성하면 콤보박스를 폼 필드로 감쌀 수 있어요. 폼 레이아웃에 유용해요.
폼 + 커스텀 객체 (Form + Custom Object)
폼에서 커스텀 객체를 다룰 때는 표시 값보다 프로그래매틱 값을 제출해야 하는 경우가 많아요. 이 예시는 숨은 입력 필드를 사용해 커스텀 객체 매핑과 폼 제출을 결합하는 방법을 보여줘요.
핵심은 itemToValue를 사용해 무엇을 제출할지 정의하는 반면, itemToString은 사용자가 보는 것을 제어한다는 거예요. 숨은 입력 필드가 폼 제출을 위한 프로그래매틱 값을 캡처해요.
이 예시에서 사용자는 "🇺🇸 United States"를 보지만, 폼은 "US"를 제출해요.
Hook Form
이 예시는 Controller 컴포넌트를 사용해 Combobox를 React Hook Form과 통합하는 방법을 보여줘요. 폼은 숨은 입력 필드 없이도 자동으로 항목의 value 속성을 받아요.
사용자는 "React"를 보지만, 폼은 "react"를 받아요.
비활성화 상태 (Disabled State)
Combobox.Root에 disabled prop을 전달하면 콤보박스 전체를 비활성화할 수 있어요.
비활성화 항목 (Disabled Item)
드롭다운에서 특정 항목을 비활성화하려면 컬렉션 항목에 disabled prop을 추가해 주세요.
const items = [
{ label: "Item 1", value: "item-1", disabled: true },
{ label: "Item 2", value: "item-2" },
]
const { collection } = useListCollection({
initialItems: items,
// ...
})
입력 그룹 (Input Group)
InputGroup과 결합해 아이콘이나 다른 요소를 추가할 수 있어요.
유효하지 않음 (Invalid)
Combobox.Root에 invalid prop을 전달하면 오류 상태를 보여줄 수 있어요.
제어된 값 (Controlled Value)
value와 onValueChange prop을 사용하면 콤보박스 값을 프로그래매틱하게 제어할 수 있어요.
스토어 (Store)
콤보박스를 제어하는 또 다른 방법은 Combobox.RootProvider 컴포넌트와 useCombobox 스토어 훅을 사용하는 거예요.
import { Combobox, useCombobox } from "@chakra-ui/react"
function Demo() {
const combobox = useCombobox()
return (
<Combobox.RootProvider value={combobox}>{/* ... */}</Combobox.RootProvider>
)
}
이렇게 하면 콤보박스 밖에서도 콤보박스 상태와 메서드에 접근할 수 있어요.
제어된 열림 (Controlled Open)
open과 onOpenChange prop을 사용하면 콤보박스의 열림 상태를 프로그래매틱하게 제어할 수 있어요.
대용량 데이터셋 제한 (Limit Large Datasets)
대용량 목록을 관리하는 권장 방법은 useListCollection 훅의 limit 속성을 사용하는 거예요. 이렇게 하면 성능을 개선하기 위해 DOM에서 렌더링되는 항목 수가 제한돼요.
가상화 (Virtualization)
대안으로 @tanstack/react-virtual 패키지의 가상화를 활용해 대용량 데이터셋을 효율적으로 렌더링할 수 있어요.
링크 (Links)
asChild prop을 사용하면 콤보박스 항목을 링크로 렌더링할 수 있어요.
커스텀 라우터 링크의 경우 Combobox.Root 컴포넌트의 navigate prop을 커스터마이즈할 수 있어요.
Tanstack Router를 사용하는 예시예요.
import { Combobox } from "@chakra-ui/react"
import { useNavigate } from "@tanstack/react-router"
function Demo() {
const navigate = useNavigate()
return (
<Combobox.Root
navigate={({ href }) => {
navigate({ to: href })
}}
>
{/* ... */}
</Combobox.Root>
)
}
값 재수화 (Rehydrate Value)
콤보박스에 defaultValue가 있지만 컬렉션이 아직 로드되지 않은 경우, 값을 재수화하고 입력 값을 채우는 방법의 예시예요.
커스텀 항목 (Custom Item)
드롭다운에서 항목의 모양을 자신만의 컴포넌트로 커스터마이즈할 수 있어요.
커스텀 필터 (Custom Filter)
항목의 여러 속성을 일치시키는 커스텀 필터의 예시예요.
커스텀 애니메이션 (Custom Animation)
콤보박스의 애니메이션을 커스터마이즈하려면 Combobox.Content 컴포넌트에 _open과 _closed prop을 전달해 주세요.
다이얼로그에서 열기 (Open From Dialog)
다이얼로그나 팝오버 컴포넌트 안에서 콤보박스를 사용하려면 Combobox.Positioner를 Portal로 감싸는 것을 피해 주세요.
-<Portal>
<Combobox.Positioner>
<Combobox.Content>
{/* ... */}
</Combobox.Content>
</Combobox.Positioner>
-</Portal>
Dialog를 사용하면서 scrollBehavior="inside"를 설정했다면 다음을 해야 해요:
- 콤보박스가 다이얼로그에 잘리는 것을 방지하기 위해 콤보박스 포지셔닝을
fixed로 설정한다. - 트리거가 화면 밖으로 스크롤되면 콤보박스를 숨기도록
hideWhenDetached를true로 설정한다.
<Combobox.Root positioning={{ strategy: "fixed", hideWhenDetached: true }}>
{/* ... */}
</Combobox.Root>
생성 가능 (Creatable)
사용자가 목록에 없는 값을 입력해 새 옵션을 만들 수 있게 하는 예시예요. 더 부드러운 통합과 관리를 위해 useCombobox와 Combobox.RootProvider 컴포넌트를 사용해요.
참고: 이 예시는 완전히 테스트되지 않았어요. 시작점으로 사용하고 필요에 따라 개선해 주세요.
가이드 (Guides)
값 제어하기 (Controlling the value)
제어 모드에서는 value와 onValueChange를 사용해요. 필터링이 활성화된 상태에서 값을 외부에서 변경할 때(예: 폼 리셋, 동기화), 선택된 항목이 필터링되면 입력이 비어 보일 수 있어요. 업데이트 전에 reset()을 호출해 주세요:
const { collection, filter, reset } = useListCollection({
initialItems: items,
filter: contains,
})
// When changing value externally, reset the filter first
const setValueWithReset = (v: string[]) => {
reset()
setValue(v)
}
Props
Root
Combobox 컴포넌트의 Root 부분에 전달할 수 있는 prop을 확인해 주세요.
Item
Combobox 컴포넌트의 Item 부분에 전달할 수 있는 prop을 확인해 주세요.
Explorer
Combobox 컴포넌트의 각 부분을 인터랙티브하게 탐색해 보세요. 사이드바에서 부분을 클릭하면 미리보기에서 강조 표시돼요.
더 알아보기 (Learn more)
Chakra UI의 Combobox 컴포넌트에 대해 더 자세히 알아보려면 공식 문서와 Ark UI Combobox 문서를 확인해 보세요.