Pruébalo en tu web
01
Define el comportamiento
¿Es un desplegable, una pestaña o un diálogo? Escoge el patrón que corresponde a la tarea.
02
Recorre sus estados
Prueba cerrado, abierto, vacío, con resultados y con error cuando sean aplicables.
03
Comprueba cómo vuelves
Al cerrar o deshacer, la persona debe saber dónde está y poder continuar.
CASO SIMULADO
Un diálogo ficticio de reserva debe permitir cancelar con un botón y con Escape; al cerrar, el foco vuelve al control que lo abrió.
Qué hacer con el resultado
Si el ejemplo solo cambia de aspecto pero no conserva foco ni estado, aún no está listo para integrarlo.
Para profundizar
Abrir la guía completa, el código y las fuentes
Un componente no termina cuando se parece al diseño. Debe explicar su propósito, responder a las formas de interacción previstas y conservar una posición comprensible al cambiar de estado. La solución más sencilla que resuelve la tarea suele reducir tanto barreras como mantenimiento.
Para quién: diseño y desarrollo. Esta guía reúne contratos de comportamiento y ejemplos didácticos. Para nombres, estados y ocultación consulta WAI-ARIA; para casos extensos tienes guías propias de formularios y navegación.
Antes de programar: decide si necesitas el componente
| Necesidad | Solución sencilla | Cuándo añadir complejidad |
|---|---|---|
| Leer condiciones breves | Texto visible con encabezado. | Desplegable si es información secundaria extensa. |
| Comparar dos opciones | Secciones visibles o una tabla. | Pestañas si alternar vistas es mejor que compararlas a la vez. |
| Editar varios datos | Una página o sección de formulario. | Diálogo para una tarea breve que deba interrumpir temporalmente la principal. |
| Elegir una categoría | Enlaces o un select nativo. | Filtro dinámico si aporta valor mantener el contexto. |
| Recorrer resultados | Paginación con enlaces. | Carga adicional cuando preserve orientación, acceso al pie y recuperación del punto de lectura. |
Desplegables y acordeones
Para revelar una explicación secundaria, details y summary proporcionan una base nativa sin JavaScript. El resumen describe lo que contiene, admite activación con teclado y comunica su estado mediante el navegador. No escondas instrucciones imprescindibles antes de una acción dentro de un bloque que probablemente nadie abra.
<details>
<summary>¿Qué cuenta como error en una tarea?</summary>
<p>Una acción que aleja a la persona del resultado definido.
Anota también si pudo recuperarse sin ayuda.</p>
</details>
Probar el desplegable: ¿qué cuenta como error?
Una acción que aleja a la persona del resultado definido. Anota también si pudo recuperarse sin ayuda. Este bloque es una demostración didáctica del elemento nativo.
Si necesitas un acordeón personalizado, cada encabezado contiene un botón que controla su panel, mantiene aria-expanded y referencia el panel. Intro o Espacio alternan su apertura; Tab recorre controles normales. Las flechas entre cabeceras son una opción del patrón, no algo que puedas anunciar sin implementarlo. Evita convertir muchos paneles en regiones nombradas sin necesidad.
Comprueba: abrir y cerrar con teclado; escuchar o inspeccionar el estado; conservar enlaces del panel en el orden de foco cuando está abierto y excluirlos cuando está cerrado. Decide explícitamente si pueden quedar varios paneles abiertos. En el ejemplo nativo sí pueden hacerlo.
Pestañas: una vista seleccionada, un contrato distinto
Úsalas para paneles relacionados que se consultan de uno en uno. Si el lector necesita comparar datos simultáneamente o seguir un texto de principio a fin, unas secciones visibles son más sencillas. Un conjunto de enlaces a páginas distintas no necesita convertirse en pestañas ARIA.
- La lista se expone como
tablistcon nombre; cadatabreferencia sutabpanely el panel se nombra con su pestaña. - Una pestaña tiene
aria-selected="true"y participa en Tab; las demás usantabindex="-1". - En disposición horizontal, flechas izquierda/derecha desplazan el foco. Home y End pueden incorporarse para los extremos.
- En activación manual, Intro o Espacio seleccionan la pestaña enfocada. La activación automática solo conviene si mostrar el panel no introduce una espera perceptible.
- Los paneles no seleccionados quedan ocultos y sus controles fuera del recorrido. Si el panel seleccionado carece de contenido enfocable apropiado al inicio, considera hacerlo enfocable.
Comprueba: diferencia entre foco y selección; movimiento circular entre pestañas; entrada y salida con Tab; ocultación real de los paneles; estado al cambiar de ancho. Estas instrucciones describen el contrato: no son un fragmento de código listo para copiar. El patrón APG enlazado al final ofrece ejemplos completos que debes adaptar y probar.
Diálogos: abre una tarea y devuelve el contexto
Un diálogo modal interrumpe la página y restringe la interacción al diálogo. Necesita un nombre, una forma visible de cerrar, foco inicial apropiado y retorno a un destino lógico. Para una explicación breve, un desplegable evita esa interrupción. Para una edición larga o con navegación propia, suele convenir una página.
El siguiente ejemplo completo utiliza dialog.showModal(): el navegador gestiona la modalidad y Escape. El contenido es una ayuda breve, no una operación destructiva. El foco inicial va al botón de cerrar; al salir vuelve al botón que lo abrió. No hace falta añadir un role="dialog" redundante.
<button type="button" id="abrir-ayuda" hidden>Ayuda para registrar un hallazgo</button>
<dialog id="ayuda-hallazgo" aria-labelledby="titulo-ayuda">
<h2 id="titulo-ayuda">Registrar un hallazgo</h2>
<p>Anota la tarea, el problema observado y la evidencia.</p>
<form method="dialog">
<button autofocus>Cerrar ayuda</button>
</form>
</dialog>
<noscript><p>Para registrar un hallazgo, anota la tarea, el problema y la evidencia.</p></noscript>
<script>
const abrir = document.getElementById("abrir-ayuda");
const dialogo = document.getElementById("ayuda-hallazgo");
if (typeof dialogo.showModal === "function") {
abrir.hidden = false;
abrir.addEventListener("click", () => dialogo.showModal());
dialogo.addEventListener("close", () => abrir.focus());
} else {
dialogo.setAttribute("open", "");
}
</script>
Límites del ejemplo: está pensado para navegadores con soporte de dialog; sin JavaScript ofrece la misma instrucción como texto. La rama de compatibilidad deja la ayuda visible. En un formulario largo, mover el foco a un título estático con tabindex="-1" puede orientar mejor; no reutilices el mismo destino inicial para cualquier contenido. Si el disparador desaparece al completar una operación, el retorno debe ir a otro punto lógico.
Comprueba: Tab y Mayús+Tab permanecen dentro mientras es modal, Escape y el botón cierran, el fondo no se puede operar y el foco regresa. Hazlo también con zoom y ventana estrecha. No marques aria-modal="true" en una falsa ventana que deja interactuar con el fondo.
Búsqueda y filtros
Una búsqueda necesita etiqueta, campo, acción y un resultado comprensible. Conserva el término buscado y permite editarlo. En cero resultados, muestra la consulta y una forma razonable de continuar: ampliar términos, quitar filtros o explorar una sección. No presentes un error de conexión como «sin resultados».
Para filtros simples, usa controles nativos y un botón «Aplicar filtros» cuando actualizar con cada cambio interrumpiría la tarea. Agrupa opciones relacionadas y muestra qué filtros están activos. «Restablecer» debe tener un alcance evidente. Si actualizas sin recargar, conserva el foco en el control, anuncia un resumen mediante un estado apropiado y evita respuestas antiguas que sobrescriban una consulta posterior.
Comprueba: combinaciones de filtros, cero coincidencias, carga lenta, fallo y reintento; vuelta desde un resultado; funcionamiento con teclado; conservación del estado en la URL cuando el producto permite compartir o recuperar la búsqueda. No conviertas un select corriente en un combobox personalizado solo para cambiar su aspecto.
Tablas que se puedan interpretar
Usa tablas para relaciones entre filas y columnas, no para maquetar toda una página. Un título o caption identifica el conjunto; las celdas de cabecera usan th y, en estructuras simples, scope="col" o scope="row". Si requiere múltiples niveles de asociación, valora primero dividirla en tablas más sencillas.
<table>
<caption>Resultados de dos tareas ficticias</caption>
<thead>
<tr><th scope="col">Tarea</th><th scope="col">Completada</th></tr>
</thead>
<tbody>
<tr><th scope="row">Localizar una guía</th><td>Sí</td></tr>
<tr><th scope="row">Encontrar una fuente</th><td>No</td></tr>
</tbody>
</table>
Si se ordenan columnas, el encabezado contiene un botón y aria-sort refleja la columna ordenada. El cambio debe afectar a los datos, no solo al icono. En móvil, permite desplazamiento local cuando sea necesario sin perder la asociación de cabeceras. Una tabla estática no necesita roles de cuadrícula interactiva.
Paginación y carga adicional
Para páginas de resultados, ofrece enlaces con destino real dentro de una navegación con nombre. Marca la página actual mediante aria-current="page"; el enlace o texto visible debe comunicar el número. «Anterior» y «Siguiente» necesitan estados coherentes en los extremos. Unos puntos sin nombres ni indicación de posición dificultan saber dónde estás.
Si «Cargar más» añade resultados al final, conserva una posición comprensible y comunica cuántos se han añadido. No saltes automáticamente al comienzo de la página. Comprueba acceso al pie, recuperación al volver desde una ficha y un final de lista reconocible. El desplazamiento infinito no es obligatorio para que una interfaz resulte moderna.
Avisos y estados: carga, vacío, error y éxito
| Estado | Información necesaria | Qué evitar |
|---|---|---|
| Cargando | Qué se está esperando y, cuando proceda, cómo cancelar. | Un indicador visual sin explicación o una animación continua innecesaria. |
| Vacío inicial | Qué contendrá el área y cuál es el primer paso. | Culpar al usuario de no tener datos. |
| Sin coincidencias | Qué consulta o filtros se aplicaron y cómo ampliarlos. | Confundirlo con un fallo del servicio. |
| Error | Qué no se completó, qué se conserva y qué se puede intentar. | Mensajes técnicos sin una salida o pérdida de lo ya escrito. |
| Éxito | Qué acción terminó y cuál es el siguiente paso, si existe. | Confirmar antes de recibir respuesta del servidor. |
Usa estados no urgentes para actualizaciones de contexto y alertas solo cuando la urgencia lo justifique. aria-busy puede comunicar que una región se actualiza, pero requiere restablecer su valor y no aporta por sí mismo un mensaje comprensible. Si hay una operación larga, no dejes a la persona adivinando si su acción se recibió.
Una ficha de revisión por componente
Antes de aceptarlo, registra propósito, semántica, teclas, foco inicial y final, estados, funcionamiento móvil y alternativa si falla una dependencia. Añade una evidencia de cada estado importante. Un resultado automático sin errores es útil; no demuestra que el diálogo devuelve el contexto ni que el filtro permite completar la tarea.
