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
labelstring—Label rendered above the control.
hintstring—Helper text rendered below the control.
errorstring—Error message that replaces `hint` and enables error styling.
optionsComboboxOption[]—Available options.
valuestring—Selected value in controlled mode.
defaultValuestring—Initial selected value in uncontrolled mode.
onChange(value: string, option: ComboboxOption) => void—Called with the selected value and option.
placeholderstring—Trigger text when no option is selected. Default: `"Select…"`.
searchPlaceholderstring—Search input placeholder. Default: `"Search…"`.
emptyMessagestring—Text shown when filtering finds no options. Default: `"No results."`.
disabledboolean—Disables the trigger.
defaultOpenboolean—Whether the popup starts open. Useful for demos.
idstring—Id for the trigger. A stable id is generated when omitted.
classNamestring—Additional class name appended to `.lyra-combobox`.

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

OpçãoTipoObrigatóriaDescrição
optionsLyraComboboxOption[]—Available data options. Default: `[]`.
valuestring—Initially selected option value; also the modelable selected value.
openboolean—Whether the popup initially starts open; also modelable. Default: `false`.
placeholderstring—Trigger text with no selected option. Default: `"Select…"`.
searchPlaceholderstring—Search input placeholder. Default: `"Search…"`.
emptyMessagestring—Text shown when filtering finds no options. Default: `"No results."`.
disabledboolean—Disables the trigger. Default: `false`.
idstring—Stable id base; one is generated from the root when omitted.
errorboolean—Applies the React field error modifier to the trigger. Default: `false`.
describedBystring—Consumer-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——
labelnull—Country
hintnull—Choose one
errornull—Required
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'],
    ]"
/>