Combobox

Selector con búsqueda typeahead para colecciones dinámicas que crecen con los datos (colaboradores, puestos, departamentos, cuentas contables). Para enums y listas cortas (<~20 opciones fijas) usá un <select class="cl-input"> nativo — un typeahead de 3 opciones es peor UX que un select.

El DS distribuye solo el patrón visual: las clases .cl-combobox* y el contrato de markup/ARIA de abajo. El comportamiento (filtrado, teclado, estado ARIA) lo aporta la app consumidora con su propio JS, siguiendo el patrón combobox editable de WAI-ARIA APG.

Degradación sin JS

Renderizá server-side un <select class="cl-input"> nativo dentro del wrapper y dejá que el JS de la app lo reemplace al conectar: sin JS el select sigue funcionando. El select queda oculto pero en el DOM (es el control que viaja en el form); el input de texto y la lista los construye el JS.

<div class="cl-combobox">
  <select class="cl-input" name="employee[position_id]">
    <option value=""></option>
    <option value="3" data-meta="Ventas">Gerente de Ventas</option>
  </select>
</div>

Anatomía (post-enhancement)

Input con role="combobox" + lista popover con role="listbox". La lista se oculta con el atributo nativo hidden. El resaltado de teclado usa .is-active (foco virtual vía aria-activedescendant); la opción elegida lleva aria-selected="true". El demo muestra el estado abierto congelado.

  • Gerente Administrativo Administración
  • Gerente de Ventas Ventas
<div class="cl-combobox">
  <select class="cl-input" name="employee[position_id]" hidden></select>
  <input class="cl-input" type="text" role="combobox"
         aria-expanded="true" aria-controls="positions-list"
         aria-autocomplete="list" aria-activedescendant="positions-list-opt-3"
         autocomplete="off" placeholder="Buscar puesto...">
  <ul class="cl-combobox-list" id="positions-list" role="listbox">
    <li class="cl-combobox-option" role="option" id="positions-list-opt-1">
      <span>Analista de Nómina</span>
      <span class="cl-combobox-option-meta">Administración</span>
    </li>
    <li class="cl-combobox-option is-active" role="option" id="positions-list-opt-3" aria-selected="true">
      <span>Gerente de Ventas</span>
      <span class="cl-combobox-option-meta">Ventas</span>
    </li>
  </ul>
</div>

Sin resultados

Cuando el filtro no matchea nada, mostrá una única fila no interactiva con .cl-combobox-empty.

  • No se encontraron resultados
<ul class="cl-combobox-list" role="listbox">
  <li class="cl-combobox-empty">No se encontraron resultados</li>
</ul>

Contrato de comportamiento (lo implementa la app)