En este tema, aprenderemos cómo crear widgets de JavaScript que sean accesibles para todos los usuarios, incluidas las personas con discapacidades. Los widgets de JavaScript, como menús desplegables, pestañas y carruseles, son componentes interactivos comunes en las aplicaciones web modernas. Asegurarse de que estos elementos sean accesibles es crucial para proporcionar una experiencia inclusiva.

Conceptos Clave

  1. Accesibilidad del Teclado: Asegúrate de que todos los widgets sean navegables y operables mediante el teclado.
  2. Roles y Propiedades ARIA: Utiliza ARIA (Accessible Rich Internet Applications) para mejorar la accesibilidad de los widgets.
  3. Gestión del Enfoque: Controla el enfoque del teclado para que los usuarios sepan dónde están en la página.
  4. Mensajes de Estado: Proporciona retroalimentación visual y auditiva sobre el estado de los widgets.

Accesibilidad del Teclado

Los usuarios deben poder interactuar con los widgets utilizando solo el teclado. Esto incluye:

  • Navegación: Usa las teclas de flecha para moverte entre elementos.
  • Activación: Usa la tecla Enter o Espacio para activar elementos seleccionables.
  • Escape: Usa la tecla Esc para cerrar menús o diálogos.

Ejemplo de Código: Menú Desplegable Accesible

<button id="menuButton" aria-haspopup="true" aria-expanded="false">Menú</button>
<ul id="menu" role="menu" hidden>
  <li role="menuitem" tabindex="-1">Opción 1</li>
  <li role="menuitem" tabindex="-1">Opción 2</li>
  <li role="menuitem" tabindex="-1">Opción 3</li>
</ul>

<script>
  const menuButton = document.getElementById('menuButton');
  const menu = document.getElementById('menu');
  const menuItems = menu.querySelectorAll('[role="menuitem"]');

  menuButton.addEventListener('click', () => {
    const expanded = menuButton.getAttribute('aria-expanded') === 'true';
    menuButton.setAttribute('aria-expanded', !expanded);
    menu.hidden = expanded;
    if (!expanded) {
      menuItems[0].focus();
    }
  });

  menuItems.forEach(item => {
    item.addEventListener('keydown', (event) => {
      switch (event.key) {
        case 'ArrowDown':
          event.preventDefault();
          const next = item.nextElementSibling || menuItems[0];
          next.focus();
          break;
        case 'ArrowUp':
          event.preventDefault();
          const prev = item.previousElementSibling || menuItems[menuItems.length - 1];
          prev.focus();
          break;
        case 'Escape':
          menuButton.focus();
          menuButton.click();
          break;
      }
    });
  });
</script>

Explicación del Código

  • aria-haspopup y aria-expanded: Indican que el botón controla un menú desplegable y su estado (abierto o cerrado).
  • role="menu" y role="menuitem": Definen el rol del contenedor y los elementos del menú para tecnologías de asistencia.
  • tabindex="-1": Permite que los elementos sean enfocados programáticamente.
  • Gestión del Enfoque: El enfoque se mueve entre los elementos del menú usando las teclas de flecha.

Roles y Propiedades ARIA

ARIA es esencial para mejorar la accesibilidad de los widgets. Aquí hay algunas propiedades comunes:

  • aria-live: Anuncia cambios dinámicos en el contenido.
  • aria-controls: Indica qué elemento controla un widget.
  • aria-labelledby: Asocia un elemento con su etiqueta.

Ejercicio Práctico

Tarea: Crea un carrusel de imágenes accesible que permita la navegación con el teclado y proporcione descripciones de las imágenes.

Solución

  1. HTML Estructura:
<div id="carousel" role="region" aria-labelledby="carouselLabel">
  <h2 id="carouselLabel">Galería de Imágenes</h2>
  <div role="list">
    <div role="listitem" tabindex="0">
      <img src="image1.jpg" alt="Descripción de la imagen 1">
    </div>
    <div role="listitem" tabindex="-1">
      <img src="image2.jpg" alt="Descripción de la imagen 2">
    </div>
    <div role="listitem" tabindex="-1">
      <img src="image3.jpg" alt="Descripción de la imagen 3">
    </div>
  </div>
  <button id="prevButton" aria-label="Imagen anterior">Anterior</button>
  <button id="nextButton" aria-label="Imagen siguiente">Siguiente</button>
</div>
  1. JavaScript Funcionalidad:
const carousel = document.getElementById('carousel');
const items = carousel.querySelectorAll('[role="listitem"]');
let currentIndex = 0;

document.getElementById('prevButton').addEventListener('click', () => {
  items[currentIndex].setAttribute('tabindex', '-1');
  currentIndex = (currentIndex === 0) ? items.length - 1 : currentIndex - 1;
  items[currentIndex].setAttribute('tabindex', '0');
  items[currentIndex].focus();
});

document.getElementById('nextButton').addEventListener('click', () => {
  items[currentIndex].setAttribute('tabindex', '-1');
  currentIndex = (currentIndex === items.length - 1) ? 0 : currentIndex + 1;
  items[currentIndex].setAttribute('tabindex', '0');
  items[currentIndex].focus();
});

Retroalimentación

  • Error Común: No establecer tabindex correctamente puede impedir que los elementos sean enfocados.
  • Consejo: Siempre prueba tus widgets con un lector de pantalla y solo con el teclado para asegurarte de que sean accesibles.

Conclusión

Crear widgets de JavaScript accesibles es esencial para una web inclusiva. Al implementar accesibilidad del teclado, usar roles y propiedades ARIA, y gestionar el enfoque adecuadamente, puedes mejorar significativamente la experiencia de usuario para todos. En el siguiente tema, exploraremos cómo asegurar la accesibilidad del teclado en más profundidad.

© Copyright 2024. Todos los derechos reservados