Combobox

Combobox é o controle de escolha pesquisável para listas longas demais para percorrer de uma vez. Ele mantém o foco DOM no campo de busca enquanto aria-activedescendant identifica a opção ativa, então filtrar e navegar pelo teclado não desloca o foco pela lista.

Exemplos

Opções pesquisáveis

Use rótulos curtos que as pessoas consigam prever ao digitar. O hint opcional da opção dá contexto para diferenciar escolhas parecidas sem transformar o resultado em outro parágrafo.

Type to narrow a longer list.

Seleção controlada

Passe value e onChange quando outra parte da tela possuir a escolha. Sem value, defaultValue inicia o valor selecionado pelo próprio componente.

Quando usar

Use Combobox para uma escolha em uma lista conhecida quando filtrar tornar essa escolha materialmente mais rápida de encontrar.

Prefira outro componente quando:

  • A lista é curta e não precisa de filtro — use Select e mantenha o seletor nativo do navegador.
  • Poucas opções mutuamente exclusivas devem ser comparadas de relance — use Radio, em vez de escondê-las.
  • A pessoa está inserindo um valor que não se limita às opções — use Input ou Textarea, conforme o comprimento.

Acessibilidade

  • O gatilho expõe aria-haspopup="listbox", aria-expanded e aria-controls; seu popup contém uma role="listbox" com itens role="option".
  • Quando aberto, o foco vai para a busca (role="combobox"). Ela usa aria-activedescendant para a opção ativa e a reinicia após filtrar.
  • Seta para cima/baixo muda a opção ativa; Enter a seleciona; Escape fecha o popup e devolve o foco ao gatilho.
  • Um label nomeia a busca com aria-labelledby; sem ele, o placeholder da busca vira aria-label. Dica ou erro descreve ambos os controles.

API e código

NomeTipoObrigatóriaDescrição
labelstringLabel rendered above the control.
hintstringHelper text rendered below the control.
errorstringError message that replaces `hint` and enables error styling.
optionsComboboxOption[]Available options.
valuestringSelected value in controlled mode.
defaultValuestringInitial selected value in uncontrolled mode.
onChange(value: string, option: ComboboxOption) => voidCalled with the selected value and option.
placeholderstringTrigger text when no option is selected. Default: `"Select…"`.
searchPlaceholderstringSearch input placeholder. Default: `"Search…"`.
emptyMessagestringText shown when filtering finds no options. Default: `"No results."`.
disabledbooleanDisables the trigger.
defaultOpenbooleanWhether the popup starts open. Useful for demos.
idstringId for the trigger. A stable id is generated when omitted.
classNamestringAdditional class name appended to `.lyra-combobox`.

x-data="lyraCombobox({ … })"

OpçãoTipoObrigatóriaDescrição
optionsLyraComboboxOption[]Available data options. Default: `[]`.
valuestringInitially selected option value; also the modelable selected value.
openbooleanWhether the popup initially starts open; also modelable. Default: `false`.
placeholderstringTrigger text with no selected option. Default: `"Select…"`.
searchPlaceholderstringSearch input placeholder. Default: `"Search…"`.
emptyMessagestringText shown when filtering finds no options. Default: `"No results."`.
disabledbooleanDisables the trigger. Default: `false`.
idstringStable id base; one is generated from the root when omitted.
errorbooleanApplies the React field error modifier to the trigger. Default: `false`.
describedBystringConsumer-owned field-message id used for `aria-describedby`.

Mantenha alinhados os ids do gatilho, da busca e da listbox. O foco DOM permanece na busca; aria-activedescendant identifica a opção ativa sem mover o foco para dentro da lista:

html
<div class="lyra-field">
  <label class="lyra-label" id="country-label" for="country">País</label>
  <span class="lyra-combobox">
    <button
      class="lyra-input lyra-combobox__trigger"
      id="country"
      type="button"
      aria-haspopup="listbox"
      aria-expanded="true"
      aria-controls="country-listbox"
    >
      <span class="lyra-combobox__placeholder">Escolha um país</span>
    </button>
    <div class="lyra-combobox__pop">
      <div class="lyra-combobox__search">
        <input
          role="combobox"
          aria-expanded="true"
          aria-controls="country-listbox"
          aria-autocomplete="list"
          aria-activedescendant="country-option-0"
          aria-labelledby="country-label"
        />
      </div>
      <div class="lyra-combobox__list" id="country-listbox" role="listbox">
        <button
          class="lyra-combobox__option lyra-combobox__option--active"
          id="country-option-0"
          role="option"
          tabindex="-1"
          aria-selected="false"
        >
          Brasil
        </button>
      </div>
    </div>
  </span>
</div>

<lyra:combobox> Gerado do lyra-ds/blade v0.10.0.

O comportamento vem de lyraCombobox() — instale @lyra-ds/alpine e veja a aba HTML + Alpine.

PropPadrãoObrigatóriaValores de exemplo
options[]
valuenull
defaultOpenfalse
labelnullCountry
hintnullChoose one
errornullRequired
placeholdernull
searchPlaceholdernull
emptyMessagenull
disabledfalse
factory'lyraCombobox'
extraOptions[]
blade
<lyra:combobox
    label="Assignee"
    placeholder="Select a teammate"
    search-placeholder="Search teammates"
    empty-message="No teammate found."
    :options="[
        ['value' => 'ana', 'label' => 'Ana Ribeiro'],
        ['value' => 'joao', 'label' => 'João Martins'],
        ['value' => 'mei', 'label' => 'Mei Tanaka'],
    ]"
/>