Fallo Común F79 de WCAG 2.1: No determinar programáticamente el estado de enfoque

La accesibilidad digital es clave para que todas las personas puedan interactuar con la web sin barreras. Uno de los errores comunes en la accesibilidad es cuando el estado de enfoque de un componente de la interfaz de usuario no se puede determinar mediante programación o no se notifica el cambio de estado de enfoque a las tecnologías de asistencia.

Este problema, identificado como F79 en WCAG 2.1, afecta el cumplimiento del Criterio de Conformidad 4.1.2: Nombre, Función y Valor. Para los usuarios de lectores de pantalla y magnificadores de pantalla, la correcta gestión del enfoque es fundamental, ya que les permite navegar e interactuar con los componentes de una página web.

Acerca de este fallo

El fallo F79 ocurre cuando un componente de la interfaz de usuario no informa correctamente sobre su estado de enfoque a través de las APIs de accesibilidad. Esto provoca que tecnologías de asistencia, como lectores de pantalla, no puedan identificar en qué elemento se encuentra el usuario, lo que dificulta la navegación y la interacción con la web.

Escenarios comunes del fallo:

  • Menús personalizados que no exponen qué elemento está enfocado.
  • Formularios con campos de entrada personalizados que no notifican el cambio de enfoque.
  • Widgets interactivos creados con JavaScript que manejan eventos de teclado y ratón, pero no informan del estado de enfoque a las tecnologías de asistencia.
  • Pestañas o acordeones que no indican programáticamente qué panel está activo.

Ejemplos

Ejemplo incorrecto 1: Menú sin exposición del estado de enfoque

Este código crea un menú interactivo usando JavaScript, pero no permite que el teclado ni las tecnologías de asistencia detecten el elemento enfocado.

<ul id=»menu»>
<li class=»menu-item»>Inicio</li>
<li class=»menu-item»>Servicios</li>
<li class=»menu-item»>Contacto</li>
</ul>

<script>
let items = document.querySelectorAll(‘.menu-item’);
let index = 0;

document.addEventListener(‘keydown’, function(event) {
if (event.key === «ArrowDown») {
items[index].classList.remove(‘active’);
index = (index + 1) % items.length;
items[index].classList.add(‘active’);
}
});
</script>

🔴 Problema:

  • No hay enfoque real en los elementos, por lo que el usuario de teclado y los lectores de pantalla no pueden determinar qué elemento está activo.
  • Los li no son elementos interactivos y no se pueden enfocar con Tab.

Solución correcta: Uso de tabindex y focus()

Para hacer accesible este menú sin usar ARIA, simplemente permitimos que los elementos sean focalizables con tabindex="0" y forzamos el focus() cuando el usuario navega.

<ul id=»menu»>
<li class=»menu-item» tabindex=»0″>Inicio</li>
<li class=»menu-item» tabindex=»0″>Servicios</li>
<li class=»menu-item» tabindex=»0″>Contacto</li>
</ul>

<script>
let items = document.querySelectorAll(‘.menu-item’);
let index = 0;

document.addEventListener(‘keydown’, function(event) {
if (event.key === «ArrowDown») {
items[index].blur(); // Quitamos foco del anterior
index = (index + 1) % items.length;
items[index].focus(); // Enfocamos el nuevo
}
});
</script>

¿Qué mejora?

  • Ahora, los usuarios pueden navegar usando Tab y Flechas.
  • El elemento tendrá enfoque real, permitiendo su identificación por lectores de pantalla.

Ejemplo incorrecto 2: Campo de entrada sin notificación de cambio de enfoque

El siguiente código usa un div para simular un campo de entrada, pero no es accesible porque no se puede enfocar con el teclado ni es reconocido como un input.

<div id=»custom-input» tabindex=»0″>Escriba aquí…</div>

<script>
let input = document.getElementById(‘custom-input’);

input.addEventListener(‘click’, function() {
input.innerText = «»;
});
</script>

🔴 Problema:

  • Aunque tabindex="0" hace el elemento focalizable, no es un campo de entrada real.
  • No permite la entrada de texto con el teclado.
  • No se puede navegar correctamente con lectores de pantalla.

Solución correcta: Uso de <input> en lugar de div

Si queremos que sea accesible sin ARIA, lo mejor es usar un input real:

<label for=»custom-input»>Nombre:</label>
<input type=»text» id=»custom-input» placeholder=»Escriba aquí…»>

¿Qué mejora?

  • El input es accesible por defecto, sin necesidad de scripts adicionales.
  • Se puede navegar con Tab y escribir sin problemas.
  • Funciona con lectores de pantalla sin requerir ARIA.

Ejemplo incorrecto 3: Botón con div sin notificación de enfoque

A veces, los desarrolladores crean botones usando div, lo que rompe la accesibilidad:

<div id=»custom-button» tabindex=»0″>Enviar</div>

<script>
let button = document.getElementById(‘custom-button’);
button.addEventListener(‘click’, function() {
alert(«Formulario enviado»);
});
</script>

🔴 Problema:

  • Aunque el div es focalizable con tabindex="0", no se comporta como un botón.
  • No se puede activar con la tecla Enter o Espacio, lo que impide su uso con teclado.
  • No informa su función a tecnologías de asistencia.

Solución correcta: Usar <button> en lugar de div

<button id=»custom-button»>Enviar</button>

<script>
let button = document.getElementById(‘custom-button’);
button.addEventListener(‘click’, function() {
alert(«Formulario enviado»);
});
</script>

¿Qué mejora?

  • Se puede activar con Enter y Espacio sin necesidad de agregar eventos adicionales.
  • Tiene enfoque nativo y se reconoce como un botón sin requerir role="button".
  • Es 100% accesible sin necesidad de ARIA.

Ejemplo correcto: Solución ideal

Este ejemplo presenta un menú accesible, un formulario con etiquetas correctamente asociadas y un botón funcional sin necesidad de ARIA.

📌 Recuerda: Es mejor una página sin ARIA que con mal ARIA. Siempre debemos usar el elemento HTML semántico correcto en lugar de usar ARIA, si tal elemento existe.

<!DOCTYPE html>
<html lang=»es»>
<head>
<meta charset=»UTF-8″>
<meta name=»viewport» content=»width=device-width, initial-scale=1.0″>
<title>Ejemplo Accesible Sin ARIA</title>
<style>
/* Estilos para mejorar la visibilidad del enfoque */
:focus {
outline: 3px solid #ffcc00;
}

/* Menú accesible */
nav ul {
list-style: none;
padding: 0;
}

nav ul li {
display: inline-block;
margin-right: 20px;
}

nav ul li a {
text-decoration: none;
padding: 5px;
}

/* Enfoque visible */
nav ul li a:focus {
outline: 3px solid #ffcc00;
background-color: #0056b3;
color: white;
}
</style>
</head>
<body>

<h1>Ejemplo de elementos interactivos accesibles</h1>

<!– ✅ Menú accesible con enfoque visible –>
<nav>
<ul>
<li><a href=»#inicio»>Inicio</a></li>
<li><a href=»#servicios»>Servicios</a></li>
<li><a href=»#contacto»>Contacto</a></li>
</ul>
</nav>

<!– ✅ Formulario accesible con etiquetas asociadas –>
<form>
<label for=»nombre»>Nombre:</label>
<input type=»text» id=»nombre» name=»nombre»>

<label for=»email»>Correo electrónico:</label>
<input type=»email» id=»email» name=»email»>

<!– ✅ Botón accesible sin ARIA –>
<button type=»submit»>Enviar</button>
</form>

<script>
// Funcionalidad para garantizar que el foco se mueva correctamente en el menú con el teclado
document.addEventListener(‘keydown’, function(event) {
const menuItems = document.querySelectorAll(‘nav ul li a’);
let currentIndex = Array.from(menuItems).findIndex(item => item === document.activeElement);

if (event.key === «ArrowRight») {
currentIndex = (currentIndex + 1) % menuItems.length;
menuItems[currentIndex].focus();
}

if (event.key === «ArrowLeft») {
currentIndex = (currentIndex – 1 + menuItems.length) % menuItems.length;
menuItems[currentIndex].focus();
}
});
</script>

</body>
</html>

Interfaz accesible con menú de navegación, formulario con etiquetas correctamente asociadas y botón funcional, asegurando el enfoque visible y la navegación con teclado sin necesidad de ARIA.

¿Qué mejora?

  • Menú accesible: Los enlaces son elementos nativos <a>, lo que los hace navegables con Tab.
  • Formularios correctamente etiquetados: Cada campo de entrada tiene un <label> asociado con for.
  • Enfoque visible: Se mantiene el indicador de enfoque con outline, resaltando los elementos al navegar con el teclado.
  • Navegación con teclado mejorada: Se permite mover entre los elementos del menú con las teclas de flecha izquierda y derecha.
  • Sin necesidad de ARIA: Se utiliza HTML semántico y propiedades CSS nativas para garantizar la accesibilidad.

Errores comunes y cómo evitarlos

Errores frecuentes:

  1. Usar divs o spans para elementos interactivos en lugar de etiquetas HTML adecuadas (button, input, select)
  2. No permitir que los usuarios de teclado detecten el foco en los elementos.
  3. No asignar tabindex="0" a elementos personalizados que necesitan ser focalizables.
  4. Eliminar el enfoque visual con outline: none; sin una alternativa clara.

Cómo evitar estos errores:

  • Usar etiquetas HTML nativas en lugar de crear widgets personalizados.
  • Mantener el focus() en los elementos interactivos y asegurar que sea visible.
  • Permitir la navegación con teclado (Tab, Shift+Tab, Enter, Espacio).
  • Evitar eliminar el contorno de enfoque sin una alternativa clara.

Preguntas frecuentes sobre el fallo F79

¿Por qué es importante que el estado de enfoque sea programáticamente identificable?

Porque los lectores de pantalla y otras tecnologías de asistencia dependen de esta información para guiar a los usuarios a través de la página.

¿Qué pasa si un usuario no puede identificar el foco?

Puede quedar atrapado en la navegación o seleccionar elementos incorrectos sin darse cuenta.

¿Es obligatorio usar ARIA para gestionar el enfoque?

No en elementos nativos de HTML (<button>, <input>, <select>), pero es fundamental en componentes personalizados.

¿Cómo puedo probar si el enfoque es accesible?

Utiliza NVDA, VoiceOver o JAWS y navega con el teclado (Tab y Shift+Tab) para verificar que el foco se mueve correctamente.

¿Cómo afectan los menús personalizados a la accesibilidad?

Si no exponen correctamente el foco, los usuarios de lectores de pantalla pueden no saber qué opción está seleccionada.

¿El error F79 solo afecta a usuarios con discapacidad visual?

No. También impacta a usuarios con movilidad reducida que dependen del teclado para navegar.

Recursos relacionados

Pruebas y validación

Procedimiento

  1. Usar solo el teclado (Tab, Shift+Tab, Enter) para comprobar que todos los elementos interactivos pueden recibir foco.
  2. Probar con un lector de pantalla (NVDA, JAWS, VoiceOver) para verificar que informa correctamente qué elemento está enfocado.
  3. Usar herramientas de validación de accesibilidad en navegadores como Chrome Lighthouse o WAVE.

Resultados esperados

  • ✅ Si los usuarios de teclado y lectores de pantalla detectan correctamente el estado de enfoque, el contenido cumple con WCAG.
  • ❌ Si no hay notificación de cambio de foco, el contenido falla el criterio 4.1.2 y debe corregirse.

🚀 Garantizar una navegación accesible beneficia a todos los usuarios. ¿Necesitas ayuda para mejorar la accesibilidad de tu sitio? Contáctanos para una auditoría accesible. 💡

¿Tienes dudas? Solicita una consultoría inicial gratuita

Evaluamos tu sitio web para identificar barreras que dificultan el acceso a personas con discapacidad. Te entregamos un informe con errores detectados y soluciones para que tu web sea usable por todos.