Accesibilidad del teclado: cómo hacer que tu sitio web sea totalmente navegable con el teclado

La accesibilidad mediante teclado es uno de los aspectos más críticos —y más descuidados— de la accesibilidad web, y los estudios muestran que el 85% de los sitios web todavía no ofrecen una navegación por teclado adecuada. Esta guía abarca los requisitos de las WCAG, los patrones de fallo más comunes y técnicas prácticas a nivel de código para ayudar a desarrolladores y responsables de cumplimiento a crear experiencias verdaderamente navegables con el teclado.

Imagina intentar completar una solicitud de empleo, reservar una cita médica o finalizar una compra en línea… y que tu mouse no funcione. No está roto, solo es irrelevante: navegas únicamente presionando Tab, Enter y las teclas de flecha. Para millones de personas en todo el mundo, esto no es un experimento mental. Personas con discapacidades motoras, lesiones por esfuerzo repetitivo, discapacidades visuales y quienes dependen de lectores de pantalla confían en la navegación por teclado como su interfaz principal con la web. Sin embargo, la investigación muestra de forma consistente que el 85% de los sitios web no ofrecen una navegación por teclado adecuada, dejando a estas personas fuera de tareas digitales básicas todos los días. Si tu sitio está en esa mayoría, esta guía es para ti.

Quién depende de la navegación por teclado — y por qué importa más de lo que crees

La accesibilidad por teclado no es una preocupación de nicho para un pequeño grupo de personas. La población que depende de ella es más amplia y diversa de lo que la mayoría de los desarrolladores imagina. Personas con discapacidades físicas que no pueden usar un mouse, personas ciegas que no pueden ver el puntero en pantalla y personas con afecciones crónicas como lesiones por esfuerzo repetitivo que deben limitar el uso del mouse dependen de la navegación por teclado como su puerta de entrada a la web. Más allá de la discapacidad, muchas personas usuarias avanzadas — desarrolladores, redactores, profesionales de entrada de datos — prefieren los atajos de teclado por su rapidez y eficiencia.

Las personas usuarias de lectores de pantalla representan otro grupo importante. Los lectores de pantalla interpretan y anuncian los elementos de la página en función del foco y de la estructura semántica, y las personas se desplazan por el contenido con pulsaciones de teclas. Si un sitio web no mantiene el foco del teclado o no admite un orden de foco lógico, la navegación con lector de pantalla se descompone por completo. El software de reconocimiento de voz como Dragon NaturallySpeaking también genera eventos de teclado, lo que significa que una mala compatibilidad con el teclado también rompe la navegación controlada por voz.

El argumento empresarial es igualmente convincente. Según los datos disponibles, las personas con discapacidad en EE. UU. poseen casi medio billón de dólares en ingresos disponibles. Cuando tu sitio web no es accesible por teclado, estás rechazando activamente una parte significativa de ese mercado. La exposición legal también es real: la accesibilidad por teclado es esencial para la conformidad con WCAG, que es el punto de referencia para el cumplimiento de la ADA, la Sección 508, la European Accessibility Act y la EN 301 549 a nivel global. Los “keyboard traps” — donde una persona se queda atrapada dentro de un elemento de la página sin forma de salir — se citan como fallos claros de WCAG que han aparecido en demandas relacionadas con accesibilidad.

Quizá lo más revelador: el 71% de las personas con discapacidad simplemente abandonará un sitio web que les resulte difícil de usar. No se quejan. Se van. Y dado que los problemas de accesibilidad por teclado tienden a concentrarse en los puntos de interacción más críticos — formularios, modales, menús de navegación y flujos de pago — el daño recae directamente sobre tus tasas de conversión.

El marco de WCAG: lo que realmente exigen las reglas

Las Web Content Accessibility Guidelines (WCAG) organizan los requisitos de teclado principalmente bajo la Pauta 2.1 — “Hacer que toda la funcionalidad esté disponible desde un teclado”. Entender qué se exige y qué no es el primer paso hacia el cumplimiento. WCAG 2.2, que se convirtió en el estándar oficial del W3C el 5 de octubre de 2023 y añadió nueve nuevos criterios de éxito al marco existente, es ahora el estándar recomendado para la ADA, la Sección 508 y la European Accessibility Act.

Los criterios de éxito clave relacionados con el teclado que debes conocer son:

  • SC 2.1.1 Keyboard (Nivel A): Toda la funcionalidad debe ser operable mediante una interfaz de teclado sin requerir tiempos específicos para pulsaciones individuales, excepto cuando la función subyacente requiera una entrada dependiente de la trayectoria (como el dibujo a mano alzada). Este es el mínimo — todo elemento interactivo debe ser alcanzable y operable con el teclado.
  • SC 2.1.2 No Keyboard Trap (Nivel A): Si el foco del teclado puede moverse a un componente usando el teclado, el foco también debe poder moverse fuera usando solo el teclado. Si se requiere un método no estándar para salir, se debe informar a las personas usuarias. Los keyboard traps son un bloqueo absoluto para quienes usan el teclado.
  • SC 2.4.3 Focus Order (Nivel A): Si una página web puede navegarse de forma secuencial, el orden del foco debe preservar el significado y la operabilidad. Un orden de tabulación lógico y predecible es innegociable.
  • SC 2.4.7 Focus Visible (Nivel AA): Cualquier interfaz de usuario operable por teclado debe tener un modo en el que el indicador de foco del teclado sea visible. Las personas usuarias deben poder ver siempre dónde se encuentran en la página.
  • SC 2.4.11 Focus Not Obscured (Minimum) (Nivel AA — nuevo en WCAG 2.2): Cuando un elemento enfocable con el teclado recibe el foco, no debe quedar completamente oculto por contenido creado por el autor, como encabezados fijos o banners de cookies.
  • SC 2.4.12 Focus Not Obscured (Enhanced) (Nivel AAA): Una versión más estricta que exige que ninguna parte del componente enfocado quede oculta por contenido creado por el autor.
  • SC 2.5.8 Target Size (Minimum) (Nivel AA — nuevo en WCAG 2.2): Los objetivos interactivos deben tener al menos 24x24 píxeles CSS, reduciendo errores para personas con control motor limitado.
  • SC 2.5.7 Dragging Movements (Nivel AA — nuevo en WCAG 2.2): Cualquier funcionalidad que requiera arrastrar debe tener una alternativa de un solo puntero — lo que, por extensión, beneficia a quienes usan teclado y no pueden realizar operaciones de arrastre.

WCAG 2.2 es totalmente compatible hacia atrás con WCAG 2.1 — añade criterios pero no elimina ninguno (excepto el ahora obsoleto 4.1.1 Parsing). Si tu sitio ya cumple con WCAG 2.1 AA, solo necesitas implementar los seis nuevos criterios de Nivel AA. Para la accesibilidad por teclado específicamente, la gran novedad es garantizar que los elementos enfocados nunca queden completamente ocultos por elementos fijos de la página — un problema muy común en el mundo real que WCAG 2.1 no abordaba explícitamente.

El principio de WCAG es sencillo de enunciar y exigente de implementar: si toda la funcionalidad puede lograrse usando el teclado, puede ser utilizada por personas que usan teclado, entrada por voz, teclados en pantalla y una amplia variedad de tecnologías de asistencia que generan pulsaciones de teclas simuladas. Ninguna otra forma de entrada tiene esta flexibilidad ni está universalmente soportada.

Los fallos de accesibilidad por teclado más comunes (y qué los causa)

Las auditorías manuales revelan de forma consistente que los problemas de accesibilidad por teclado se encuentran entre las barreras de accesibilidad más comunes y disruptivas en la web. En un estudio a gran escala, el 54% de las páginas con formularios presentaban problemas de accesibilidad por teclado que afectaban acciones críticas como tabular entre campos de formulario, cerrar ventanas emergentes o pulsar botones de Enviar. Las personas evaluadoras se veían obligadas con frecuencia a abandonar carritos de compra o recargar páginas tras quedar atrapadas en elementos que no podían controlar solo con el teclado.

Las causas raíz se agrupan en torno a unos pocos patrones recurrentes que vale la pena examinar en detalle.

1. Manejadores de eventos solo para mouse. Usar onmouseover, onmouseout u onclick en elementos <div> sin manejadores de eventos equivalentes para teclado es uno de los fallos más comunes. Un <div> con un manejador de clic no es un botón — no tiene un rol implícito de teclado, no recibe foco mediante Tab y no responde a Enter o Space. Añadir role='button' mediante ARIA ayuda a los lectores de pantalla, pero aún requiere que agregues manualmente tabindex='0', así como manejadores onkeydown y onkeyup. La solución correcta casi siempre es usar un elemento <button> real.

2. Contornos de foco suprimidos. Uno de los problemas más extendidos es la regla CSS outline: none o outline: 0 aplicada de forma global o a elementos enfocados. Las personas diseñadoras suelen eliminar el anillo de foco predeterminado del navegador porque se ve poco estético en ciertos temas. El resultado es que quienes usan el teclado no tienen idea de dónde están en la página. Esto es una violación directa de WCAG SC 2.4.7 y uno de los problemas más fáciles de crear — y de corregir.

3. Keyboard traps en modales, widgets e iframes. Los cuadros de diálogo modales que no restringen el foco correctamente permiten que Tab avance más allá del modal hacia contenido de fondo oculto, haciendo que el modal sea imposible de cerrar con el teclado. Los widgets de terceros — herramientas de chat, reproductores de video, selectores de fecha, incrustaciones de mapas — son especialmente propensos a esto porque su gestión interna del teclado es opaca para ti.

4. Orden de tabulación ilógico. El orden de navegación por teclado predeterminado viene determinado por el orden del DOM. Cuando las personas desarrolladoras usan CSS Grid, Flexbox o posicionamiento CSS para reordenar la presentación visual de forma independiente del orden del DOM, el foco de Tab salta por la pantalla de maneras completamente desconectadas del diseño visual. Los valores positivos de tabindex (por ejemplo, tabindex='2') usados para forzar un orden específico empeoran significativamente este problema en la mayoría de los casos reales.

5. Menús desplegables solo por hover. Los menús de navegación que se abren solo al pasar el mouse por encima, sin disparador de teclado, dejan a las personas usuarias de teclado varadas. Este es un patrón extremadamente común en menús desplegables solo con CSS, donde los submenús aparecen con :hover pero nunca se exponen a la navegación basada en foco.

6. Foco no devuelto tras interacciones dinámicas. Cuando se cierra un modal, cajón o panel desplegable, el foco debe volver al elemento que lo activó. Si no lo hace — si aterriza en la parte superior de la página o desaparece en una ubicación indeterminada — la persona usuaria se pierde por completo. Las aplicaciones dinámicas de una sola página son particularmente vulnerables a esto.

Construir bien la accesibilidad por teclado: implementación práctica

Con los patrones de fallo en mente, así es como se ve una implementación correcta en las áreas más importantes de un sitio web típico.

Usa primero HTML semántico

Los elementos HTML nativos son accesibles por teclado de forma predeterminada. Los enlaces (<a href>), botones (<button>), campos de formulario, selects y textareas participan en el orden de tabulación, responden a pulsaciones estándar y comunican su rol a las tecnologías de asistencia — todo sin una sola línea adicional de JavaScript. Un elemento <button> tiene automáticamente el rol correcto, es accesible por teclado, responde a Enter y Space y tiene una gestión de foco adecuada incorporada. Añadir role='button' a un <div> proporciona el rol correcto, pero aún requiere que implementes manualmente la compatibilidad con teclado y la gestión del foco. Prefiere siempre HTML semántico.

<!-- Avoid: non-semantic div pretending to be a button -->
<div onclick='doSomething()' class='btn'>Submit</div>

<!-- Correct: native button element -->
<button type='button' onclick='doSomething()'>Submit</button>

Corrige tus indicadores de foco

En lugar de eliminar el contorno predeterminado del navegador, sustitúyelo por un indicador de foco personalizado con estilo. WCAG 2.2 SC 2.4.11 exige que el área del indicador de foco sea al menos tan grande como un perímetro de 2 píxeles CSS de grosor del componente sin foco, con una relación de contraste de al menos 3:1 entre los estados enfocado y no enfocado. Usa la pseudoclase :focus-visible en lugar de :focus para mostrar indicadores de foco solo a quienes usan teclado, sin afectar la estética de la interacción con mouse.

/* Remove default only to replace with better indicator */
*:focus {
  outline: none;
}

*:focus-visible {
  outline: 3px solid #005fcc;
  outline-offset: 3px;
  border-radius: 2px;
}

Este enfoque te da control visual completo mientras mantienes el cumplimiento con WCAG. Asegúrate de que el color del foco tenga suficiente contraste tanto con el fondo como con el propio componente, especialmente en sitios con temas oscuros o sobre imágenes.

Gestiona el foco en interacciones dinámicas

Cuando el contenido cambia de forma dinámica — al abrir un modal, cargar contenido nuevo o eliminar un elemento — debes gestionar el foco de forma programática. Al abrir un modal, mueve el foco al primer elemento enfocable dentro de él. Al cerrar, devuelve el foco al elemento disparador. Usa el método .focus() de JavaScript para esto. Para atrapar el foco dentro de un modal correctamente, intercepta los eventos de teclas Tab y Shift+Tab y cicla el foco entre el primer y el último elemento enfocable dentro del cuadro de diálogo.

// Opening a modal: move focus inside
function openModal(modalEl, triggerEl) {
  modalEl.removeAttribute('hidden');
  const firstFocusable = modalEl.querySelector(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  if (firstFocusable) firstFocusable.focus();
}

// Closing a modal: return focus to trigger
function closeModal(modalEl, triggerEl) {
  modalEl.setAttribute('hidden', '');
  triggerEl.focus();
}

Implementa enlaces para saltar la navegación

Las personas que usan teclado deben presionar Tab para navegar por cada elemento interactivo antes del contenido principal — encabezados, menús de navegación, barras de búsqueda — en cada carga de página. Los enlaces para saltar son la solución: un enlace visualmente oculto en la parte superior de la página que se vuelve visible al recibir foco y lleva a las personas directamente al área de contenido principal. Son un requisito de Nivel A de WCAG y uno de los logros rápidos más impactantes disponibles.

<!-- Place as the first element in <body> -->
<a href='#main-content' class='skip-link'>Skip to main content</a>

<!-- Target anchor on the main content container -->
<main id='main-content' tabindex='-1'>
  <!-- page content -->
</main>
/* Show skip link only on keyboard focus */
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px 16px;
  z-index: 100;
  transition: top 0.2s;
}

.skip-link:focus {
  top: 0;
}

Construye menús de navegación accesibles

Los menús de navegación con submenús desplegables requieren especial atención. El patrón de interacción correcto con teclado para un menú de navegación es: Tab se mueve entre los elementos de nivel superior; Enter o Space abre un submenú; las teclas de flecha navegan dentro del submenú; y Escape cierra el submenú y devuelve el foco al disparador. Usa atributos ARIA para comunicar el estado. Los menús que se abren solo con hover y sin disparador de teclado no son accesibles y deben corregirse.

<nav aria-label='Main navigation'>
  <ul role='menubar'>
    <li role='none'>
      <button
        aria-haspopup='true'
        aria-expanded='false'
        aria-controls='products-menu'>
        Products
      </button>
      <ul role='menu' id='products-menu' hidden>
        <li role='none'>
          <a role='menuitem' href='/software'>Software</a>
        </li>
        <li role='none'>
          <a role='menuitem' href='/hardware'>Hardware</a>
        </li>
      </ul>
    </li>
  </ul>
</nav>

Usa aria-expanded='false' y aria-expanded='true' alternados mediante JavaScript para comunicar el estado abierto/cerrado. Usa aria-haspopup='true' para indicar que al activar el botón se revela un submenú. Asegúrate de que la tecla Escape cierre el submenú y devuelva el foco al botón disparador.

Maneja tabindex correctamente

Hay tres valores significativos de tabindex y cada uno tiene un propósito distinto. tabindex='0' añade un elemento no interactivo al orden natural de tabulación — úsalo cuando realmente necesites que un elemento no enfocable (como el contenedor de un widget personalizado) reciba foco. tabindex='-1' elimina un elemento del orden de tabulación pero permite que reciba foco de forma programática mediante .focus() — esencial para objetivos de modales y destinos de enlaces para saltar. Los valores positivos de tabindex (como tabindex='1' o tabindex='5') anulan el orden natural de formas que casi siempre causan más problemas de los que resuelven; evítalos por completo y corrige el orden del DOM en su lugar.

ARIA: una herramienta potente, no una solución mágica

Los atributos Accessible Rich Internet Applications (ARIA) amplían la semántica de HTML para ayudar a las tecnologías de asistencia a entender componentes personalizados que el HTML nativo no cubre — pestañas, acordeones, vistas de árbol, carruseles, cuadros combinados. Los atributos ARIA pueden proporcionar contexto adicional, pero deben complementar — no sustituir — al HTML semántico. Un error común y peligroso es recurrir a ARIA antes de considerar si un elemento HTML nativo podría hacer el trabajo en su lugar.

La primera regla de ARIA es: no uses ARIA si un elemento o atributo HTML nativo puede hacer el mismo trabajo. La segunda regla: ninguna ARIA es mejor que una ARIA incorrecta. Un marcado ARIA incorrecto — por ejemplo, aplicar role='menu' sin la jerarquía adecuada de elementos secundarios con role='menuitem', o usar aria-hidden='true' en un elemento que recibe foco — puede perjudicar activamente la accesibilidad en lugar de ayudarla.

Cuando ARIA es realmente necesaria, los atributos más útiles para interacciones con teclado son: aria-expanded para comunicar el estado abierto/cerrado en elementos colapsables; aria-controls para vincular un disparador con el contenido que controla; aria-haspopup para indicar que un botón abre un menú o cuadro de diálogo; aria-modal='true' en elementos de diálogo para indicar que el contenido de fondo es inerte; y regiones aria-live (polite para mensajes de estado, assertive para alertas urgentes) para anunciar cambios de contenido dinámico a quienes usan lectores de pantalla sin mover el foco.

Una consideración sutil pero importante: lectores de pantalla como NVDA y JAWS usan sus propios atajos de teclado — por ejemplo, pulsar H en NVDA mueve a la persona usuaria al siguiente encabezado de la página. Las personas desarrolladoras deben evitar crear atajos de aplicación personalizados que entren en conflicto con estos comandos de tecnologías de asistencia.

Pruebas de accesibilidad por teclado

La prueba más efectiva que puedes ejecutar ahora mismo no requiere herramientas: desconecta tu mouse y navega por tu sitio web usando solo el teclado. Presiona Tab para avanzar por los elementos interactivos, Shift+Tab para retroceder, Enter para activar enlaces y botones, Space para alternar casillas de verificación y activar botones, Escape para cerrar modales y menús, y las teclas de flecha para navegar dentro de los componentes. Pregúntate: ¿puedes llegar a cada elemento interactivo? ¿Puedes ver en todo momento dónde estás? ¿Puedes completar cada recorrido de usuario crítico sin quedarte atrapado?

Las herramientas automatizadas pueden detectar un subconjunto significativo de problemas de accesibilidad por teclado — en particular etiquetas faltantes, botones vacíos y algunos problemas de gestión de foco. Herramientas como axe DevTools, WAVE y Lighthouse son buenos primeros filtros. Sin embargo, las herramientas automatizadas detectan solo alrededor del 40% de los problemas de WCAG. La visibilidad del foco, el orden lógico del foco y la gestión correcta del estado ARIA requieren evaluación manual humana. Para la evaluación más exhaustiva, combina el escaneo automatizado con pruebas manuales solo con teclado en varios navegadores e incluye pruebas con lectores de pantalla como NVDA (Windows), JAWS (Windows) o VoiceOver (macOS/iOS).

Algunos escenarios específicos que debes probar manualmente cada vez que publiques un nuevo componente o página: ¿puedes abrir y cerrar cada desplegable, modal y acordeón usando solo Tab, Enter y Escape? Cuando se cierra un modal, ¿el foco vuelve al disparador? ¿El enlace para saltar la navegación aparece y funciona al primer toque de Tab? ¿Hay puntos en los que el foco de Tab desaparece dentro de un elemento sin indicador visible? ¿Los encabezados fijos o banners de cookies ocultan elementos enfocados mientras tabulas por la página?

Para equipos que construyen bibliotecas de componentes, la WAI-ARIA Authoring Practices Guide (APG) publicada por W3C es la referencia definitiva para patrones de interacción con teclado en docenas de tipos de widgets — desde acordeones y carruseles hasta selectores de fecha y vistas de árbol. Cada patrón especifica exactamente qué teclas deben ser compatibles y cuál debe ser el comportamiento esperado.

Encabezados fijos, pies de página fijos y foco oculto

Uno de los requisitos nuevos más relevantes en la práctica en WCAG 2.2 es el Criterio de Éxito 2.4.11: Focus Not Obscured. Aborda un problema tan común que prácticamente define la web moderna: barras de navegación fijas, banners de consentimiento de cookies, widgets de chat y pies de página fijos que se superponen al contenido de la página. Cuando una persona que usa teclado tabula hasta un elemento que se ha desplazado detrás de una de estas capas fijas, el elemento enfocado se vuelve invisible — la persona no puede ver con qué está interactuando.

La solución requiere coordinación entre CSS y JavaScript. Cuando un elemento recibe foco, el navegador debe desplazarlo a un área visible. Pero un encabezado fijo con position: fixed y una altura de, digamos, 80px significa que los primeros 80px de la ventana gráfica están ocupados de forma permanente. El “scroll padding” de CSS puede compensar esto:

html {
  /* Height of your sticky header + a small buffer */
  scroll-padding-top: 96px;
}

Esto indica al navegador que desplace el anclaje de scroll en la cantidad especificada, de modo que cuando desplaza automáticamente un elemento enfocado a la vista, tenga en cuenta el encabezado fijo. Es posible que también necesites un scroll-padding-bottom equivalente si tienes un pie de página fijo. Para banners de cookies u overlays que aparecen y desaparecen, asegúrate de que tengan valores de z-index que no cubran el elemento enfocado, o ajusta dinámicamente el “scroll padding” cuando el banner esté visible.

Conclusiones clave

  • El HTML semántico es tu mejor primer paso. Los elementos nativos como <button>, <a> y los controles de formulario son accesibles por teclado de forma predeterminada. Cada widget personalizado construido con divs te cuesta accesibilidad que luego tendrás que reconstruir manualmente con ARIA y JavaScript.
  • Nunca suprimas los indicadores de foco sin reemplazarlos. La regla global outline: none es una de las cosas más dañinas que puedes poner en una hoja de estilos. Usa :focus-visible para proporcionar un anillo de foco con estilo y alto contraste que cumpla los requisitos mínimos de tamaño y contraste de WCAG 2.2.
  • Gestiona el foco de forma programática en cada interacción dinámica. Los modales, cajones, notificaciones emergentes (“toast”) y cambios de contenido dinámico requieren una gestión explícita del foco — mover el foco hacia dentro y devolverlo al cerrar. Sin esto, las personas que usan teclado pierden su lugar cada vez que la interfaz cambia.
  • Añade un enlace para saltar la navegación en la parte superior de cada página. Requiere menos de 20 líneas de código y mejora drásticamente la experiencia de quienes usan teclado y, de otro modo, tendrían que tabular por todo tu encabezado y navegación en cada carga de página.
  • Prueba con tu teclado antes de publicar. Las herramientas automatizadas detectan solo una fracción de los problemas de accesibilidad por teclado. Un recorrido de diez minutos solo con teclado por tus recorridos de usuario más críticos revelará bloqueos reales que ningún escáner encontrará — y puede hacerlo cualquier desarrollador del equipo sin formación especializada.