Addaw, ir a inicio Donar

Lección 5 de 10 · 15 min de lectura · Revisado el 26/10/2026

Combobox, listbox y autocompletado

El buscador de estaciones de una web de transporte, el campo «Municipio» de una solicitud en la sede electrónica o el buscador con sugerencias de una tienda en línea son el mismo componente: un campo de texto que, mientras escribes, despliega una lista de opciones. La APG (se abre en una ventana nueva) lo llama combobox y es, con diferencia, el patrón que más se implementa mal. En el curso de formularios viste cuándo basta un <select> nativo; esta lección se ocupa de lo que viene después: el combobox editable, la lista de opciones (listbox) que lo acompaña y las decisiones de autocompletado. Aplica directamente la técnica aria-activedescendant de la lección «Widgets compuestos».

Antes de construir: ¿de verdad necesitas un combobox?

NecesidadSolución recomendada
Elegir una opción entre pocas (hasta 5-7)Botones de opción nativos dentro de <fieldset>
Elegir una opción de una lista conocida y no muy larga<select> nativo, que ya tiene escritura anticipada
Elegir entre cientos de valores (municipios, estaciones, productos)Combobox editable con lista filtrada
Escribir texto libre con sugerencias opcionalesCombobox con aria-autocomplete="list"
Elegir de una lista siempre visible, una o varias opcioneslistbox (o casillas de verificación nativas si son pocas)

El elemento <datalist> parece una solución nativa para las sugerencias, pero su presentación, el tamaño del texto y su comportamiento con lectores de pantalla y zoom varían entre navegadores, y apenas admite estilo. Sirve para prototipos o herramientas internas; para un servicio público o un comercio, el patrón APG te da control y resultados predecibles.

Anatomía del combobox según WAI-ARIA 1.2

En ARIA 1.2 el rol combobox se pone en el propio campo de texto, no en un contenedor que lo envuelva, como hacía el patrón de ARIA 1.1. Si encuentras código con un div role="combobox" que contiene el input, es el modelo antiguo. El modelo actual tiene estas piezas:

<label for="origen">Estación de origen</label>
<input id="origen" type="text" role="combobox"
       aria-autocomplete="list" aria-expanded="true"
       aria-controls="origen-lista" aria-activedescendant="origen-op-2"
       autocomplete="off">
<ul id="origen-lista" role="listbox" aria-label="Estaciones">
  <li id="origen-op-1" role="option" aria-selected="false">Madrid - Chamartín</li>
  <li id="origen-op-2" role="option" aria-selected="true">Madrid - Puerta de Atocha</li>
  <li id="origen-op-3" role="option" aria-selected="false">Málaga - María Zambrano</li>
</ul>
<div role="status" class="solo-lector">3 estaciones encontradas</div>
  • role="combobox" en el input, con una etiqueta visible asociada por <label>.
  • aria-expanded refleja si la lista está desplegada (true/false); actualízalo cada vez que se abra o se cierre.
  • aria-controls apunta al id de la lista emergente. La lista suele ser un listbox, que es el valor por defecto; si es otra cosa (un árbol, una rejilla o un diálogo), decláralo con aria-haspopup.
  • aria-activedescendant apunta a la opción resaltada, mientras el foco del DOM permanece en el campo para que la persona pueda seguir escribiendo. Cuando no hay ninguna resaltada, elimina el atributo o déjalo vacío.
  • Cada opción tiene role="option", un id único y aria-selected="true" en la que está resaltada.
  • autocomplete="off" evita que las sugerencias del navegador tapen las tuyas. Úsalo solo en campos como este; no lo apliques a campos de datos personales (nombre, correo, dirección), que necesitan su valor de autocomplete para cumplir 1.3.5 Identificar el propósito de la entrada.

Los cuatro tipos de autocompletado

El atributo aria-autocomplete le dice al lector de pantalla qué va a pasar mientras se escribe:

  • none: la lista no depende de lo escrito (por ejemplo, siempre muestra las cinco búsquedas recientes).
  • list: la lista se filtra con lo que se escribe. Es el caso más habitual y el más fácil de entender.
  • inline: el texto que falta se completa dentro del propio campo, seleccionado, para que se acepte o se sobrescriba.
  • both: lista filtrada y, además, completado en línea de la primera coincidencia.

El completado en línea ahorra pulsaciones, pero puede desconcertar a personas con discapacidad cognitiva o a quien dicta por voz, porque el campo contiene texto que no ha escrito. Si lo usas, que el texto añadido se vea claramente seleccionado y que Supr o seguir escribiendo lo descarte.

El teclado que hay que implementar

TeclaComportamiento
EscribirFiltra la lista y la despliega si hay resultados; no mueve el foco del campo.
Flecha abajoAbre la lista si está cerrada; si está abierta, resalta la opción siguiente.
Flecha arribaResalta la opción anterior (opcionalmente, abre la lista y resalta la última).
Alt+Flecha abajoAbre la lista sin resaltar ninguna opción.
IntroAcepta la opción resaltada, escribe su texto en el campo y cierra la lista.
EscapeCierra la lista; opcionalmente, si ya estaba cerrada, vacía el campo.
Flechas izquierda y derecha, Inicio, FinMueven el cursor dentro del texto, como en cualquier campo; no navegan por la lista.
TabCierra la lista y pasa al siguiente campo; no debe aceptar en silencio una opción que la persona no ha elegido.

Con el ratón o el dedo, un clic en una opción la acepta. Un detalle técnico evita muchos fallos: si cierras la lista en el evento blur del campo, el clic en la opción llega tarde porque la lista ya ha desaparecido. Llama a preventDefault() en el mousedown de la lista para que el campo no pierda el foco, o retrasa el cierre.

Error frecuente

Mover el foco del DOM a la primera sugerencia en cuanto aparece la lista. La persona estaba escribiendo «Mad» y, de repente, sus pulsaciones van a una opción en vez de al campo; si usa lector de pantalla, además oye un anuncio inesperado en mitad de la palabra. El foco se queda en el campo y solo Flecha abajo resalta opciones. Un error vecino: navegar a la página del resultado en cuanto se resalta una opción con las flechas, sin esperar a Intro, que incumple 3.2.2 Al recibir entradas.

Anunciar sin abrumar

Una persona ciega no ve que la lista se ha desplegado ni cuántas opciones tiene. Además de aria-expanded, una región role="status" (vista en el curso de WAI-ARIA (se abre en una ventana nueva)) informa del número de resultados: «12 estaciones encontradas. Usa las flechas para elegir». Tres reglas para que ayude en lugar de molestar:

  1. Retrasa el anuncio unos cientos de milisegundos después de la última pulsación, para no leer un recuento distinto con cada letra.
  2. No uses role="alert" para esto: interrumpe lo que el lector esté diciendo, incluido el eco de lo que se escribe.
  3. Anuncia también el vacío: «No hay estaciones que coincidan con "Madri"». Una lista que no aparece no comunica nada por sí sola.

Ejemplo

Así debería sonar con NVDA el buscador de estaciones bien hecho: al enfocar, «Estación de origen, cuadro combinado, contraído, editable». La persona escribe «mál» y, tras una pausa, oye «2 estaciones encontradas». Pulsa Flecha abajo: «Málaga - María Zambrano, 1 de 2». Intro: el campo contiene la estación y el lector anuncia «contraído». Las palabras exactas cambian según el lector y el idioma, pero los elementos son siempre los mismos: nombre, rol, estado, opción y posición.

Listbox independiente y combobox de solo selección

Un listbox también puede ir solo, siempre visible: un selector de idiomas para traducir un documento o la lista de destinatarios de una notificación. Si admite varias selecciones, lleva aria-multiselectable="true"; aria-selected marca cada opción elegida, y el modelo recomendado por la APG es que Espacio alterne la selección de la opción enfocada mientras las flechas solo se mueven. Si son pocas opciones, casillas de verificación nativas en un <fieldset> son más sencillas y nadie tiene que aprender un teclado nuevo.

La APG documenta además un combobox de solo selección (select-only combobox): un elemento no editable con role="combobox" y tabindex="0" que se comporta como un <select> personalizado. Es útil cuando el diseño exige mostrar en cada opción algo que el <select> no permite, como un icono o un texto secundario; pero cuesta bastante más mantenerlo. Pregúntate antes si un <select> estilizado no basta.

Punto clave

Combobox de ARIA 1.2: rol en el input, aria-expanded, aria-controls hacia el listbox, aria-activedescendant hacia la opción resaltada y el foco siempre en el campo. Lo que no se ve se anuncia en una región de estado, con calma y también cuando no hay resultados.

Cómo comprobarlo

  • Escribe, recorre las sugerencias con flechas, acepta con Intro, cierra con Escape y sal con Tab: el campo nunca debe perder el foco ni rellenarse solo.
  • Con lector de pantalla, comprueba que oyes el rol, el estado contraído o expandido, el recuento de resultados y cada opción con su posición.
  • Comprueba el resaltado: la opción activa debe distinguirse con algo más que el color y con un contraste mínimo de 3:1, y no quedar fuera de la vista al bajar.
  • Amplía al 400 %: la lista debe caber o desplazarse sin tapar el campo.
  • Abre el patrón Combobox de la APG y compara tu componente con sus ejemplos tecla por tecla.

Pruébalo tú

Elige un buscador con sugerencias de una web que uses a menudo (una tienda, una web de transporte o tu propia intranet). Abre el inspector, selecciona el campo y mira sus atributos: ¿tiene role="combobox", aria-expanded que cambia al escribir y aria-activedescendant que cambia al pulsar Flecha abajo? Si las sugerencias son <div> sin roles, ya sabes por qué un lector de pantalla no las anuncia.

Resumen

  • Antes de construir un combobox, descarta los botones de opción y el <select> nativo; <datalist> es poco predecible.
  • En ARIA 1.2 el rol combobox va en el campo, con aria-expanded, aria-controls y aria-activedescendant; las opciones son role="option" con aria-selected.
  • aria-autocomplete (none, list, inline, both) anuncia cómo se comporta el campo al escribir.
  • El foco no sale del campo; las flechas resaltan, Intro acepta, Escape cierra, y resaltar no es navegar (3.2.2).
  • Una región role="status" con retardo anuncia el número de resultados, incluido el cero.

Comprueba lo que has aprendido

Esta lección se puede leer libremente. Para hacer su test de 3 preguntas, los ejercicios prácticos con páginas reales, guardar tu avance y optar al examen y al certificado, matricúlate en el curso.