Combobox
Um select filtrável com chips, grupos e resultados assíncronos, em um popup que se redimensiona conforme você digita.
pnpm dlx shadcn@latest add https://hextaui.com/r/combobox.jsonAdiciona o componente, os tokens de tema do HextaUI e quaisquer componentes do HextaUI dos quais ele depende.
Adicione os tokens de tema ao seu CSS global, se ainda não o fez.
Instale as dependências.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopie e cole o código a seguir no seu projeto.
components/ui/combobox.tsx Atualize os caminhos de importação para corresponder à configuração do seu projeto.
Passe as opções para items e renderize cada uma com uma função dentro de <ComboboxList />. O combobox as filtra conforme você digita e renderiza apenas as correspondências. Objetos também funcionam: o label deles é exibido no input e o value é enviado.
Digite no campo para filtrar a lista.
Um botão mostra o valor e o campo de busca vai para dentro do popup.
Com multiple, cada item selecionado vira um chip antes do input.
Botão de limpar
showClear adiciona um botão de limpar que ocupa o lugar do chevron enquanto há um valor, então o campo nunca cresce.
Com ícones
Os ícones dentro de um item são dimensionados e atenuados para você. autoHighlight destaca a primeira correspondência durante a digitação, então Enter a seleciona.
Grupos e separadores
Passe grupos no formato { value, items } e renderize cada um com <ComboboxGroup />, <ComboboxLabel /> e <ComboboxCollection />. Grupos vazios ficam ocultos durante a filtragem.
Múltiplo
Com multiple, as seleções viram chips dentro de <ComboboxChips />. O popup permanece aberto enquanto você escolhe, Backspace no input vazio remove o último chip e as teclas de seta alternam entre os chips.
Busca dentro do popup
Use <ComboboxTrigger /> para um campo no estilo select. Coloque o input dentro de <ComboboxContent /> e ele vira uma caixa de busca com ícone, e o popup se alarga para pelo menos 15rem.
Gatilho renderizado como um Button
Passe render ao gatilho para usar qualquer botão. O popup se ancora nele e mantém ao menos a sua largura.
Controlado
Controle a seleção com value e onValueChange, e o popup com open e onOpenChange. Limpar define o valor como null.
Itens desativados, inválidos e desativados individualmente
disabled na raiz esmaece o campo e seus botões. aria-invalid no input desenha o anel de erro. Itens desativados são ignorados pelas teclas de seta.
Conteúdo longo e listas grandes
Rótulos longos e sem quebra são quebrados em vez de alargar o popup. limit limita quantas correspondências são renderizadas, o que mantém rápida uma lista de 500 itens.
Busca assíncrona
Desative a filtragem integrada com filter={null}, busque dados em onInputValueChange e mostre o progresso em <ComboboxStatus />, que o anuncia aos leitores de tela. A altura do popup é animada conforme os resultados mudam.
Dentro de uma sheet
O popup fica acima do sheet, e Escape fecha o popup antes do sheet.
Da direita para a esquerda
O popup adota a direção do campo, então o botão de limpar, os chips e os itens são espelhados sem props extras.
| Tecla | Ação |
|---|---|
| ↓↑ | Abre o popup e move o destaque pelas correspondências. Itens desativados são ignorados. |
| Enter | Seleciona o item destacado. Sem nenhum destacado, fecha o popup e deixa o formulário ser enviado. |
| Escape | Fecha o popup. Quando já está fechado, limpa o valor e o input. |
| HomeEnd | Move o cursor de texto para o início ou o fim do input. |
| Backspace | Em um input de chips vazio, remove o último chip. Em um chip em foco, remove-o. |
| ←→ | Com chips, move o foco entre os chips e de volta ao input. Espelhado em layouts da direita para a esquerda. |
| Tab | Fecha o popup e move o foco adiante. |
- Dê ao input um
<label>visível por meio deidehtmlFor, ou umaria-label. Um<ComboboxTrigger />sem texto visível também precisa de umaria-label. - O botão de chevron tem o rótulo “Show options”, o botão de limpar “Clear selection” e o botão de remover de cada chip “Remove”.
- O destaque se move com
aria-activedescendant, então o foco permanece no input enquanto você navega. - Os inputs usam fonte de 16px em telas sensíveis ao toque para que o iOS não aplique zoom, e os itens crescem para uma área de toque de 44px.
Construído sobre o combobox do Base UI. Cada parte aceita as props da primitiva que envolve; as tabelas listam as que você mais usará.
| Prop | Tipo | Padrão |
|---|---|---|
itemsAs opções. Filtradas conforme você digita e passadas à render function da lista. | Item[] | Group[] | – |
multipleSelecione vários valores, exibidos como chips. | boolean | false |
value | Value | Value[] | null | – |
defaultValue | Value | Value[] | null | – |
onValueChange | (value, details) => void | – |
open | boolean | – |
defaultOpen | boolean | false |
onOpenChange | (open: boolean, details) => void | – |
inputValue | string | – |
defaultInputValue | string | – |
onInputValueChange | (inputValue: string, details) => void | – |
filterCorrespondência personalizada. null desativa a filtragem para busca no servidor. | ((item, query, itemToString) => boolean) | null | – |
limitNúmero máximo de correspondências a renderizar. -1 significa todas. | number | -1 |
autoHighlightDestaca a primeira correspondência durante a digitação. | boolean | false |
highlightItemOnHover | boolean | true |
openOnInputClick | boolean | true |
loopFocusVolta do último item para o primeiro ao mover o destaque. | boolean | true |
itemToStringLabelTexto exibido no input para um item do tipo objeto. | (item) => string | – |
itemToStringValueValor enviado com o formulário para um item do tipo objeto. | (item) => string | – |
isItemEqualToValue | (item, value) => boolean | – |
name | string | – |
required | boolean | false |
disabled | boolean | false |
readOnly | boolean | false |
modalBloqueia a rolagem da página e os cliques externos enquanto aberto. | boolean | false |
virtualizedDefina ao renderizar itens com um virtualizador. | boolean | false |
localeLocale usado na correspondência. | Intl.LocalesArgument | – |
Fora do popup, renderiza o campo completo. Dentro de <ComboboxContent />, vira uma caixa de busca compacta.
| Prop | Tipo | Padrão |
|---|---|---|
showTriggerMostra o botão de chevron. Sempre desativado dentro do popup, a menos que definido. | boolean | true outside the popup |
showClearMostra um botão de limpar no lugar do chevron enquanto há um valor. | boolean | false |
classNameAplicado ao input group em volta do input. | string | – |
disabled | boolean | false |
placeholder | string | – |
| Atributo | Descrição |
|---|---|
data-slot="combobox-input-group" | O campo em volta do input. |
data-slot="combobox-input" | O input de texto. |
data-slot="combobox-input-actions" | Contém os botões de chevron e de limpar em uma única célula empilhada. |
data-popup-open | Presente no input enquanto o popup está aberto. |
data-popup-side | O lado em que o popup abriu. |
data-list-empty | Presente quando nada corresponde. |
data-disabled | Presente quando desabilitado. |
data-invalid | Presente quando inválido dentro de um Field do Base UI. |
| Prop | Tipo | Padrão |
|---|---|---|
childrenGeralmente um <ComboboxValue />. O chevron é adicionado depois dele. | ReactNode | – |
renderQuando definido, os estilos de campo integrados são ignorados. | ReactElement | (props, state) => ReactElement | <button> |
| Atributo | Descrição |
|---|---|
data-slot="combobox-trigger" | O botão gatilho. |
data-slot="combobox-trigger-value" | Envolve o valor truncado. |
data-slot="combobox-trigger-icon" | O chevron. Inverte-se enquanto aberto. |
data-popup-open | Presente enquanto o popup está aberto. |
data-placeholder | Presente enquanto nenhum valor está selecionado. |
| Prop | Tipo | Padrão |
|---|---|---|
childrenRenderize o valor selecionado você mesmo, por exemplo como chips. | ReactNode | (value) => ReactNode | – |
placeholderExibido enquanto nada está selecionado. | ReactNode | – |
| Prop | Tipo | Padrão |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" |
align | "start" | "center" | "end" | "start" |
sideOffset | number | 6 |
alignOffset | number | 0 |
anchorPosiciona em relação a outro elemento. O padrão é o campo. Veja useComboboxAnchor. | Element | RefObject<Element | null> | VirtualElement | (() => Element | VirtualElement | null) | null | – |
dirO padrão é a direção do campo. | "ltr" | "rtl" | – |
| Atributo | Descrição |
|---|---|
data-slot="combobox-positioner" | Posiciona o popup. |
data-slot="combobox-content" | A superfície do popup. |
data-slot="combobox-content-sizer" | Medido para animar a altura do popup conforme as correspondências mudam. |
data-open | Presente enquanto aberto. |
data-side | O lado em que abriu. |
data-align | Seu alinhamento. |
data-empty | Presente quando nada corresponde. |
data-starting-style | Presente durante a animação de entrada. |
data-ending-style | Presente durante a animação de saída. |
--combobox-item-radius | Raio do item, derivado do raio do popup menos o seu padding. |
| Prop | Tipo | Padrão |
|---|---|---|
childrenChamado para cada correspondência de items. | ReactNode | (item, index) => ReactNode | – |
| Atributo | Descrição |
|---|---|
data-slot="combobox-list" | A lista rolável. |
| Prop | Tipo | Padrão |
|---|---|---|
valueO item que esta linha representa. | Item | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descrição |
|---|---|
data-slot="combobox-item" | Uma opção. |
data-slot="combobox-item-indicator" | A marca, que cresce ao ser selecionado. |
data-highlighted | Presente enquanto destacado. |
data-selected | Presente quando selecionado. |
data-disabled | Presente quando desabilitado. |
| Prop | Tipo | Padrão |
|---|---|---|
itemsEm ComboboxGroup: os próprios itens do grupo. | Item[] | – |
childrenEm ComboboxCollection: renderiza cada correspondência. | (item, index) => ReactNode | – |
| Atributo | Descrição |
|---|---|
data-slot="combobox-group" | Um grupo de itens. |
data-slot="combobox-label" | O título do grupo. |
<ComboboxEmpty /> exibe seus filhos apenas quando nada corresponde. <ComboboxStatus /> é uma região live para mensagens de carregamento e de resultado. Ambos colapsam a nada quando vazios.
| Atributo | Descrição |
|---|---|
data-slot="combobox-empty" | A mensagem de sem resultados. |
data-slot="combobox-status" | A mensagem de status live. |
data-slot="combobox-separator" | Um divisor entre grupos. |
| Prop | Tipo | Padrão |
|---|---|---|
children | ReactNode | <IconX /> |
| Atributo | Descrição |
|---|---|
data-slot="combobox-clear" | Rotulado como “Clear selection”. |
data-visible | Presente enquanto há algo para limpar. |
| Prop | Tipo | Padrão |
|---|---|---|
classNameAplicado ao campo que envolve os chips. | string | – |
| Atributo | Descrição |
|---|---|
data-slot="combobox-chips" | O campo que contém os chips e o input. |
| Prop | Tipo | Padrão |
|---|---|---|
showRemoveMostra o botão de remover. | boolean | true |
| Atributo | Descrição |
|---|---|
data-slot="combobox-chip" | Um valor selecionado. |
data-slot="combobox-chip-label" | Seu rótulo truncado. |
data-slot="combobox-chip-remove" | Rotulado como “Remove”. |
O input de texto que fica depois dos chips. Aceita as mesmas props do input do Base UI.
| Atributo | Descrição |
|---|---|
data-slot="combobox-chips-input" | O input de chips. |
useComboboxAnchor()retorna uma ref para passar a um elemento e aanchorno conteúdo.useComboboxFilter()retorna os comparadorescontains,startsWitheendsWith, sensíveis ao locale, parafilter.useComboboxFilteredItems()lê as correspondências atuais, para contagens ou listas virtualizadas.createComboboxItems(data, { getValue })cria uma coleção de itens cujo valor de seleção é um id primitivo, como uma chave de banco de dados, em vez do objeto inteiro.comboboxFieldVariantsexpõe os estilos do campo para criar campos personalizados.
- CalendarUma grade de datas para seleção única, de intervalo e múltipla, com meses deslizantes, prévias de intervalo e dias com tamanho adequado ao toque.
- CheckboxUma caixa de seleção cujo check é desenhado na tela, com pais indeterminados, grupos e rótulos que compartilham seu hover.
- Date pickerUm botão que abre um calendário em um popover, ou em um bottom sheet no celular, para datas únicas e intervalos.
- FieldRótulos, descrições e erros ligados ao seu controle, com estados de validação e layouts para formulários.
- InputUm campo de texto com três tamanhos, estados inválido e somente leitura, estilo de validação nativa e fonte de 16px no toque para que os celulares nunca façam zoom.
- Input groupUm input com ícones, texto, botões ou uma dica de teclado anexados, compartilhando uma única borda e um único anel de foco.