Lección 10 de 10 · Caso práctico · 25 min · Revisado el 26/10/2026
Caso práctico, ejercicios y lista de comprobación
Aplicarás el protocolo de la lección anterior a un caso realista, resolverás cinco ejercicios y te llevarás una lista de comprobación para tus proyectos.
Caso práctico: la cita previa de una sede electrónica
El Ayuntamiento de Valdeolmo (ficticio) va a publicar en su sede electrónica un trámite nuevo: «Solicitar cita previa». Es una aplicación de una sola página con tres pasos: (1) servicio y oficina, (2) fecha y hora, (3) datos personales y confirmación. El equipo pide una revisión de teclado antes de publicarlo. La tarea que se prueba es la que haría cualquier vecino: pedir cita para renovar el padrón sin usar el ratón.
Paso 1: primera pulsación y enlace de salto
Al pulsar Tab por primera vez, el foco desaparece: está en el primer enlace del menú lateral para móvil, que se esconde fuera de la pantalla con transform. Son 15 paradas invisibles antes de llegar a la cabecera. Además, no hay enlace de salto.
Hallazgos: foco fantasma (2.4.7 Foco visible, 2.4.3 Orden del foco) y falta de mecanismo para saltar bloques (2.4.1). Corrección: añadir visibility: hidden al menú cerrado, como vimos en la lección sobre cómo funciona el foco, y un enlace «Saltar al contenido principal» visible al recibir el foco.
Paso 2: recorrido completo
El menú «Trámites» se despliega con :hover. Con teclado no se abre, pero sus 24 enlaces, ocultos con opacity: 0, se recorren igualmente sin verse. Más abajo, al volver con Mayús+Tab, varios campos quedan tapados por la cabecera fija de 96 píxeles, y el botón «Continuar» queda completamente cubierto por el aviso de cookies, fijado en la parte inferior.
Hallazgos: 2.1.1, 2.4.7 y 2.4.11 Foco no oculto (mínimo). Corrección: un botón «Trámites» con aria-expanded que muestra u oculta el submenú con hidden; scroll-padding-top: 96px y scroll-padding-bottom con la altura del aviso en html; y el aviso de cookies al principio del DOM, para que se pueda atender y cerrar antes de empezar. Al redactar el informe se anota que 2.4.11 es un criterio de WCAG 2.2: la EN 301 549 v3.2.1 (PDF, se abre en una ventana nueva) se basa en WCAG 2.1, así que no es exigible por esa vía, pero se registra como criterio AA de WCAG 2.2 y se corrige igualmente.
Paso 3: los controles del primer paso
El selector de oficina es un div que despliega una lista con el ratón. Con Tab no se alcanza. Hallazgo: 2.1.1 Teclado y 4.1.2 Nombre, función, valor, de gravedad bloqueante: sin oficina no hay cita. Corrección: son 14 oficinas, así que lo más sencillo y robusto es un select nativo. Si el diseño exigiera buscar por texto, sería un combobox con aria-activedescendant.
Paso 4: el calendario
Cada día del mes es un button: 31 paradas de Tab, y los días sin huecos llevan disabled, así que desaparecen de la secuencia sin explicación. Es operable, pero muy lento con conmutador. Corrección: rejilla con roving tabindex: una sola parada (el día seleccionado o el de hoy), flechas para moverse por días y semanas, Re Pág y Av Pág para cambiar de mes. Los días sin huecos pasan a aria-disabled="true", de modo que se pueden recorrer y se anuncian como no disponibles. Gravedad: moderada.
Paso 5: el cambio de paso
Al pulsar «Continuar», el paso 2 sustituye al 1. El botón desaparece del DOM, el foco cae en el body y el título de la pestaña no cambia. Hallazgo: 2.4.3 Orden del foco; quien usa lector cree que no ha pasado nada. Corrección: en cada paso, document.title = "Paso 2 de 3: fecha y hora - Cita previa - Sede electrónica" y foco en el h1 del paso con tabindex="-1".
Paso 6: la confirmación y los atajos
El diálogo «¿Confirmar la cita?» se abre añadiendo una clase: el foco sigue en el fondo, Escape no lo cierra y, al cerrar con la «X», el foco vuelve al principio de la página. Corrección: <dialog> con showModal(), foco en su título o en «Cancelar», y foco devuelto al botón que lo abrió. Por último, al escribir una pregunta en el campo «Observaciones», cada «?» abre la ayuda: el atajo de una sola tecla se dispara dentro de un campo de texto y no se puede desactivar (2.1.4). Corrección: ignorar el atajo en campos de texto y añadir la opción de desactivarlo.
| Hallazgo | Criterio | Gravedad |
|---|---|---|
| Selector de oficina inalcanzable | 2.1.1, 4.1.2 | Bloqueante |
| Modal sin gestión del foco | 2.4.3 | Grave |
| Foco perdido al cambiar de paso | 2.4.3 | Grave |
| Botón «Continuar» tapado por el aviso de cookies | 2.4.11 | Grave |
| Foco fantasma en menú lateral y submenú | 2.4.7, 2.4.3 | Grave |
| Atajo «?» activo en campos de texto | 2.1.4 | Moderado |
| Calendario con 31 paradas | Buena práctica | Moderado |
Tras corregir, se repite cada paso tal como se registró antes de cerrar la incidencia.
Ejercicios de autoevaluación
1. Un acordeón cerrado se oculta con height: 0; overflow: hidden. ¿Qué problema de teclado tiene y cómo lo resuelves?
Ver solución
Sus enlaces siguen en la secuencia de Tab aunque no se ven: foco fantasma (2.4.7). Al cerrarlo, añade el atributo hidden (o display: none); si quieres animarlo, combina la altura con visibility: hidden al final de la transición.
2. El botón «Enviar» de un formulario lleva disabled hasta que se completan los campos obligatorios. Una persona que tabula no lo encuentra y no sabe qué falta. ¿Qué alternativa propones?
Ver solución
Usar aria-disabled="true", que mantiene el botón enfocable, con aria-describedby apuntando a un texto que explique qué falta, y bloquear el envío en el manejador de click mientras el atributo valga true.
3. Un gestor de expedientes quiere el atajo «N» para «Nuevo expediente». Enumera las condiciones que debe cumplir el manejador.
Ver solución
Debe existir un ajuste para desactivarlo o reasignarlo (2.1.4); el manejador debe ignorar las pulsaciones con Ctrl, Alt o Cmd, las que tienen e.isComposing y las que ocurren en input, textarea, select o contenido editable; debe comparar e.key (no e.code) y llamar a preventDefault() solo para esa tecla. Además, el atajo debe mostrarse en la interfaz.
4. Una lista de 40 resultados de búsqueda tiene tabindex="0" en cada tarjeta y, dentro, un enlace al resultado: 80 paradas. ¿Hay que convertirla en un componente compuesto con flechas?
Ver solución
No. Es una lista de enlaces, no un control. Basta con quitar el tabindex de las tarjetas: quedan 40 paradas útiles, y el lector de pantalla ya permite saltar de enlace en enlace o por encabezados. Si se quiere toda la tarjeta clicable, se amplía el área del enlace con CSS.
5. Un botón «Filtros» abre, en su sitio y sin ser modal, un panel con casillas. Se quiere que el panel se cierre cuando el foco salga de él y también con Escape. ¿Qué evento usarías para lo primero y dónde debe quedar el foco en cada caso?
Ver solución
Un manejador de focusout en el panel que compruebe si e.relatedTarget está fuera de él; en ese caso se cierra y el foco sigue su camino, porque la persona ya se ha ido a otro sitio. Con Escape, en cambio, la persona estaba dentro: hay que cerrar el panel y devolver el foco al botón «Filtros», con aria-expanded="false".
Lista de comprobación
- Todas las tareas principales se completan sin ratón.
- Ningún componente atrapa el foco; si la salida no es estándar, se explica.
- Los atajos de una sola tecla se pueden desactivar o reasignar y no actúan en campos de texto.
- No hay
tabindexpositivos ni paradas en elementos no interactivos. - El orden del foco sigue el orden de lectura.
- El foco se ve siempre, con al menos 2 píxeles y contraste 3:1.
- Ningún elemento fijo tapa por completo el elemento enfocado.
- Lo oculto sale también de la secuencia de tabulación.
- Hay un enlace de salto visible al recibir el foco.
- Cada componente compuesto es una parada y se recorre con flechas.
- Los modales mueven, retienen y devuelven el foco y se cierran con Escape.
- En cada cambio de vista se actualiza el título y el foco va al
h1. - Si se elimina el elemento enfocado, el foco pasa a un vecino con sentido.
- La activación está en
clicky el nombre accesible contiene el texto visible.
Para seguir aprendiendo
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.