ARIA (Aplicaciones de Internet Enriquecidas y Accesibles) ofrece a las personas desarrolladoras un potente conjunto de herramientas para hacer que las interfaces web dinámicas y complejas sean accesibles para quienes usan lectores de pantalla, pero su uso incorrecto es muy frecuente y costoso. Esta guía desglosa cada categoría principal de roles ARIA, explica las reglas de oro del uso de ARIA y te muestra ejemplos de código concretos para que puedas aplicarla correctamente.
Aquí tienes una cifra aleccionadora: según el análisis de WebAIM de la página de inicio del millón de sitios web más visitados, las páginas que incluyen atributos ARIA presentan de media significativamente más errores de accesibilidad detectables que las páginas sin ARIA. Esto no es un argumento en contra de usar ARIA, sino un argumento a favor de usarlo correctamente. ARIA es una de las herramientas más potentes del conjunto moderno de accesibilidad, pero también una de las más incomprendidas. Si lo usas bien, abres tu sitio de forma significativa a millones de personas con discapacidad. Si lo usas mal, empeoras activamente su experiencia.
¿Qué es ARIA y por qué existe?
ARIA significa Accessible Rich Internet Applications (Aplicaciones de Internet Enriquecidas y Accesibles). Es un conjunto de atributos HTML, definido por la Iniciativa de Accesibilidad Web (WAI) del W3C, que permite a las personas desarrolladoras comunicar información semántica a tecnologías de asistencia como lectores de pantalla, pantallas braille y software de control por voz. Cuando un navegador renderiza una página, construye dos estructuras paralelas: el DOM (lo que ves) y el Árbol de Accesibilidad (lo que leen las tecnologías de asistencia). Los atributos ARIA te permiten modificar ese Árbol de Accesibilidad para describir con precisión qué son los componentes personalizados y cómo se comportan.
La necesidad de ARIA surgió de un problema real. HTML fue diseñado para documentos, no para aplicaciones. Cuando la web evolucionó hacia una plataforma para experiencias ricas e interactivas — interfaces con pestañas, diálogos modales, arrastrar y soltar, fuentes de datos en vivo — los elementos HTML nativos no podían transmitir a un lector de pantalla qué eran esos componentes ni cómo funcionaban. ARIA llena ese vacío. Como dice MDN, ARIA "complementa HTML para que las interacciones y widgets usados habitualmente en aplicaciones puedan transmitirse a las tecnologías de asistencia cuando no existe otro mecanismo".
ARIA no cambia la presentación visual. No añade comportamiento. No proporciona soporte de teclado automáticamente. Solo modifica lo que el Árbol de Accesibilidad expone a la tecnología de asistencia. Esta es una distinción importante, y una de las causas de muchos de los errores que cometen las personas desarrolladoras cuando recurren a ARIA como atajo.
La especificación es mantenida por el W3C como WAI-ARIA, actualmente en la versión 1.2, con la 1.3 en desarrollo activo. Proporciona una ontología de roles, estados y propiedades que, en conjunto, describen elementos de interfaz de usuario accesibles para todo el abanico de patrones web modernos.
Los tres pilares: roles, estados y propiedades
Antes de escribir una sola línea de ARIA, necesitas entender los tres bloques de construcción distintos que proporciona la especificación. No son intercambiables, y confundirlos es una de las fuentes de errores más comunes.
Los roles definen lo que un elemento es. Un rol responde a la pregunta: ¿qué tipo de cosa estoy viendo? Algunos ejemplos son button, dialog, navigation, tablist y progressbar. Se aplica un rol con el atributo role: <div role='button'>. El rol comunica el propósito del elemento a la tecnología de asistencia para que la persona usuaria sepa cómo interactuar con él.
Los estados describen la condición dinámica de un elemento, algo que cambia a medida que la persona usuaria interactúa con la página. El atributo aria-expanded indica a un lector de pantalla si una sección plegable está abierta o cerrada. aria-checked refleja si una casilla de verificación personalizada está marcada. Los estados deben mantenerse sincronizados con JavaScript; un aria-expanded='false' estático que nunca cambia no solo es inútil, sino activamente engañoso.
Las propiedades proporcionan información descriptiva, normalmente más estable, sobre un elemento. aria-label da a un elemento un nombre accesible que sustituye a su texto visible. aria-labelledby apunta a otro elemento cuyo texto actúa como etiqueta. aria-describedby enlaza con texto descriptivo complementario. aria-required indica que un campo de formulario debe rellenarse. Mientras que se espera que los estados cambien con frecuencia, las propiedades tienden a establecerse una vez y dejarse tal cual, aunque hay excepciones.
Los roles definen lo que un elemento es. Los estados definen cómo se está comportando en este momento. Las propiedades proporcionan contexto descriptivo adicional. Necesitas que los tres funcionen juntos para producir un componente personalizado completamente accesible.
La regla de oro — y por qué importa más de lo que crees
La primera regla del W3C para el uso de ARIA es inequívoca: si puedes usar un elemento o atributo HTML nativo con la semántica y el comportamiento que necesitas ya incorporados, úsalo. No recurras a ARIA en primer lugar. A esto a veces se le llama el principio de que "ningún ARIA es mejor que un mal ARIA", una frase que refleja el peligro muy real de un uso bien intencionado pero incorrecto de ARIA.
Los elementos HTML nativos llevan implícita la semántica ARIA de forma gratuita. Un elemento <button> ya se expone al Árbol de Accesibilidad como un botón. Ya es accesible mediante el teclado. Ya se activa tanto con Enter como con la barra espaciadora. Ya anuncia su etiqueta. En el momento en que escribes <div role='button'>, asumes la responsabilidad de recrear manualmente todo ese comportamiento — la gestión del teclado, la gestión del foco, las actualizaciones de estado — en JavaScript. Esto no es una preocupación teórica. Olvidar el soporte de teclado en un botón personalizado es uno de los errores con ARIA más comunes y más dañinos en producción.
Los casos en los que ARIA es realmente necesario tienden a agruparse en torno a unos pocos escenarios: cuando estás construyendo un widget complejo que no tiene equivalente en HTML (un carrusel, un cuadro combinado con autocompletado, una vista de árbol); cuando estás corrigiendo marcado heredado en el que reestructurar el DOM es demasiado costoso; cuando estás construyendo un componente web que necesita exponer semántica personalizada; o cuando el soporte de los navegadores y las tecnologías de asistencia para un elemento nativo es lo bastante inconsistente como para que el equivalente ARIA funcione de forma más fiable en la práctica.
Fuera de esos escenarios, tu primer instinto debería ser HTML semántico. Usa <nav> en lugar de <div role='navigation'>. Usa <main> en lugar de <div role='main'>. Usa <button> en lugar de <div role='button'>. Los elementos nativos son más robustos, están mejor soportados y requieren mucho menos mantenimiento.
Un recorrido por las principales categorías de roles ARIA
La especificación WAI-ARIA organiza los roles en varias categorías. Entender estas categorías te ayuda a saber qué rol usar y cuándo.
Roles de referencia (landmark)
Los roles de referencia marcan las regiones principales de una página, permitiendo que las personas usuarias de lectores de pantalla salten directamente a secciones clave mediante atajos de teclado. Los roles de referencia más utilizados son banner, navigation, main, complementary, contentinfo, search y form. Cada uno de ellos tiene un equivalente directo en HTML nativo: <header>, <nav>, <main>, <aside>, <footer>, etc. En la práctica, esto significa que los roles de referencia casi siempre son redundantes si estás usando HTML semántico moderno. Añádelos solo cuando estés atado a un marcado no semántico por razones estructurales.
<!-- Preferir esto -->
<header>
<nav>...</nav>
</header>
<main>...</main>
<footer>...</footer>
<!-- Usar ARIA solo cuando debas usar divs -->
<div role='banner'>
<div role='navigation'>...</div>
</div>
<div role='main'>...</div>
<div role='contentinfo'>...</div>
Roles de widget
Los roles de widget describen componentes interactivos que la persona usuaria manipula directamente. Aquí es donde ARIA realiza su trabajo más importante, porque muchos patrones de widgets no tienen equivalente nativo en HTML. Algunos roles de widget comunes son button, checkbox, dialog, menu, menuitem, slider, tablist, tab, tabpanel, tooltip, tree y combobox.
Cuando usas un rol de widget, asumes la responsabilidad completa de la interacción con el teclado. La Guía de Prácticas de Autoría WAI-ARIA (APG) define patrones de teclado esperados para cada tipo de widget — por ejemplo, teclas de flecha para moverse entre pestañas, Escape para cerrar un diálogo, Inicio y Fin para saltar al primer y último elemento en una lista. No implementar estos patrones significa que tu componente está técnicamente etiquetado pero es funcionalmente inutilizable para personas que solo usan el teclado.
<!-- Una interfaz de pestañas personalizada -->
<div role='tablist' aria-label='Account settings'>
<button role='tab' aria-selected='true' aria-controls='panel-profile' id='tab-profile'>
Profile
</button>
<button role='tab' aria-selected='false' aria-controls='panel-security' id='tab-security' tabindex='-1'>
Security
</button>
</div>
<div role='tabpanel' id='panel-profile' aria-labelledby='tab-profile'>
<p>Profile settings content</p>
</div>
<div role='tabpanel' id='panel-security' aria-labelledby='tab-security' hidden>
<p>Security settings content</p>
</div>
Roles de región en vivo
Las regiones en vivo son una de las características más útiles de ARIA. Permiten que las tecnologías de asistencia anuncien actualizaciones dinámicas de contenido — cosas como mensajes de estado, notificaciones de error, mensajes de chat e indicadores de carga — a personas que no pueden ver el cambio en pantalla. Sin regiones en vivo, una persona usuaria de lector de pantalla que envía un formulario podría no saber nunca si tuvo éxito o falló, a menos que el foco se mueva explícitamente al resultado.
Los roles básicos de región en vivo son alert, status, log, marquee y timer. El rol alert lleva implícito un ajuste aria-live='assertive', lo que significa que interrumpe a la persona usuaria inmediatamente; es apropiado para errores o advertencias urgentes. El rol status usa aria-live='polite', esperando a que la persona usuaria termine su tarea actual antes de anunciarse; es ideal para mensajes de éxito e indicadores de progreso.
<!-- Mensaje de estado "polite" para comentarios no urgentes -->
<div role='status' aria-live='polite' aria-atomic='true'>
<!-- Inyectar texto dinámicamente aquí con JavaScript -->
</div>
<!-- Alerta "assertive" para errores que requieren atención inmediata -->
<div role='alert'>
Please correct the errors below before submitting.
</div>
La clave de las regiones en vivo es que el contenedor debe estar presente en el DOM antes de que se inyecte el contenido dinámico. Una región en vivo que se crea y se rellena simultáneamente suele pasar desapercibida para los lectores de pantalla. Crea el contenedor al cargar la página y rellénalo con JavaScript a medida que se produzcan los eventos.
Roles de estructura de documento
Los roles de estructura de documento — como article, list, listitem, table, row, cell, figure y heading — describen la organización estructural del contenido. La mayoría de ellos han sido sustituidos por elementos HTML nativos, y MDN señala que la mayoría de los roles de estructura de documento "ya no deberían usarse, ya que los navegadores ahora admiten elementos HTML semánticos con el mismo significado". La principal excepción es cuando trabajas con entornos de renderizado personalizados, componentes web o contenido basado en SVG donde los elementos HTML nativos no están disponibles.
Propiedades ARIA esenciales que toda persona desarrolladora debería conocer
Más allá de los roles, varias propiedades ARIA aparecen constantemente en el trabajo de accesibilidad del mundo real. Estas son las que usarás con más frecuencia:
- aria-label: Proporciona un nombre accesible para un elemento cuando no hay una etiqueta de texto visible disponible o cuando el texto visible es insuficiente. Casos de uso comunes: botones solo con icono, campos de búsqueda sin etiqueta visible y botones de cierre en modales. Ten en cuenta que
aria-labelsustituye cualquier texto visible o etiqueta nativa, así que úsalo con cuidado en elementos que sí tienen texto visible. - aria-labelledby: Apunta a uno o más elementos cuyo contenido de texto actúa como nombre accesible. Es más robusto que
aria-labelpara casos complejos porque el texto de la etiqueta se mantiene sincronizado con el contenido visible. Acepta una lista de IDs de elementos separados por espacios, y las tecnologías de asistencia concatenan el texto referenciado en orden. - aria-describedby: Enlaza con texto descriptivo complementario — no un nombre, sino contexto adicional. Úsalo para conectar campos de formulario con sus mensajes de error o para asociar un tooltip con el elemento que describe. Los lectores de pantalla suelen anunciar esto después del nombre y el rol del elemento.
- aria-hidden: Elimina un elemento por completo del Árbol de Accesibilidad. Es muy útil para iconos decorativos, contenido duplicado y elementos solo visuales que crearían ruido para las personas usuarias de lectores de pantalla. Nunca apliques
aria-hidden='true'a un elemento enfocable: una persona usuaria podría seguir llegando a él con la tecla Tab, pero no recibiría ninguna información sobre él. - aria-expanded: Comunica si un elemento plegable — un desplegable, un acordeón o un widget de divulgación — está actualmente abierto o cerrado. Debe alternarse dinámicamente con JavaScript; un valor estático es peor que omitir el atributo por completo.
- aria-current: Indica el elemento actual dentro de un conjunto, y se usa más comúnmente en navegación para marcar el enlace de la página activa (
aria-current='page') o el paso actual en un proceso de varios pasos.
Errores comunes con ARIA que en realidad perjudican la accesibilidad
Dado que las páginas con ARIA tienden a mostrar más errores de accesibilidad que las que no lo tienen, vale la pena ser explícito sobre lo que falla con más frecuencia. No son casos extremos, sino patrones que aparecen en código de producción todos los días.
Usar roles ARIA en elementos con semántica nativa fuerte. Algunos elementos HTML tienen lo que la especificación llama "semántica nativa fuerte": significados profundamente integrados en el navegador que no pueden sobrescribirse de forma segura. Colocar un rol inapropiado en un <button> o un <input> puede hacer que el navegador ignore el rol ARIA por completo o producir un comportamiento contradictorio que confunda a las tecnologías de asistencia. El rol que declares debe ser apropiado para el elemento en el que lo aplicas.
Olvidar el soporte de teclado con roles de widget. El role='button' de ARIA indica a un lector de pantalla que el elemento es un botón. No hace que el elemento sea operable con el teclado. Si usas un <div> con role='button', debes añadir tabindex='0' para que sea enfocable, y debes añadir controladores de eventos tanto para las teclas Enter como Espacio. Si falta cualquiera de estas partes, se rompe la experiencia para las personas que solo usan el teclado.
<!-- Incompleto e inaccesible -->
<div role='button' onclick='doSomething()'>Submit</div>
<!-- Implementación correcta de un botón personalizado -->
<div
role='button'
tabindex='0'
onclick='doSomething()'
onkeydown='if(event.key==="Enter"||event.key===" ")doSomething()'
>Submit</div>
<!-- O, la respuesta correcta: simplemente usa un botón -->
<button onclick='doSomething()'>Submit</button>
Usar aria-hidden en elementos enfocables. Aplicar aria-hidden='true' a un elemento enfocable lo oculta del Árbol de Accesibilidad pero no de la navegación por teclado. Una persona usuaria de teclado puede seguir llegando a él con Tab, no recibir ninguna información sobre él y no tener forma de saber qué hace. Esto es un incumplimiento de WCAG 2.1 bajo el Criterio de Éxito 4.1.2 (Nombre, Rol, Valor).
Estados ARIA obsoletos. No actualizar aria-expanded, aria-checked, aria-selected y estados similares cuando la interfaz cambia deja a las personas usuarias de lectores de pantalla con una imagen fundamentalmente incorrecta de la interfaz. Un menú que se abre visualmente pero cuyo disparador sigue leyendo aria-expanded='false' es activamente engañoso.
Roles redundantes. Añadir role='navigation' a un elemento <nav>, o role='button' a un <button>, no aporta nada útil. Ensucia el código y, en ocasiones, puede confundir ciertas combinaciones de tecnologías de asistencia. Confía en la semántica nativa.
ARIA y WCAG: entender la conexión
ARIA no es WCAG. Son especificaciones separadas que funcionan juntas. WCAG (Web Content Accessibility Guidelines) define el qué, los resultados necesarios para un contenido accesible. ARIA forma parte del cómo, un mecanismo técnico para lograr algunos de esos resultados. El criterio de éxito de WCAG más relevante para ARIA es el 4.1.2: Nombre, Rol, Valor, que exige que todos los componentes de la interfaz de usuario tengan un nombre, expongan su rol a las tecnologías de asistencia y comuniquen su estado y propiedades de forma programática. ARIA es una de las herramientas principales para satisfacer este criterio en componentes personalizados.
ARIA también contribuye a varios otros criterios de éxito. Los roles de referencia contribuyen al 2.4.1 (Omitir bloques) al habilitar la navegación de salto. Las regiones en vivo suelen ser la herramienta adecuada para cumplir el 4.1.3 (Mensajes de estado) en WCAG 2.1, que exige que los mensajes de estado sean determinables de forma programática sin recibir el foco. El uso correcto de aria-label y aria-labelledby ayuda a satisfacer el 2.4.6 (Encabezados y etiquetas) y el 1.3.1 (Información y relaciones).
Vale la pena señalar que el cumplimiento de WCAG es cada vez más un requisito legal. La Ley Europea de Accesibilidad entró plenamente en vigor en junio de 2025, ampliando los requisitos obligatorios de accesibilidad a una amplia gama de servicios digitales del sector privado en los estados miembros de la UE. En Estados Unidos, la ADA se sigue interpretando como aplicable a la accesibilidad web, y los requisitos federales de la Sección 508 se aplican a organismos gubernamentales y organizaciones financiadas con fondos federales. Entender ARIA correctamente no es solo una buena práctica, sino que cada vez forma más parte de tus obligaciones de cumplimiento.
Probar tu implementación de ARIA
La única forma de saber si tu implementación de ARIA realmente funciona es probarla con tecnologías de asistencia reales. Herramientas automatizadas como axe, WAVE y Lighthouse pueden detectar infracciones estructurales — una propiedad obligatoria que falta, un rol no válido, un aria-hidden aplicado a un elemento enfocable — pero no pueden decirte si un lector de pantalla anuncia tu modal de una forma que tenga sentido, o si la navegación por teclado a través de tu widget de árbol personalizado sigue los patrones esperados.
Para las pruebas manuales, los principales lectores de pantalla que debes cubrir son JAWS y NVDA en Windows (juntos representan la gran mayoría del uso de lectores de pantalla de escritorio) y VoiceOver en macOS e iOS. TalkBack cubre Android. Cada combinación de lector de pantalla y navegador puede comportarse de forma diferente, por lo que se recomienda encarecidamente probar al menos dos combinaciones. Prueba todos los estados interactivos: abre el diálogo, expande el acordeón, selecciona la opción, dispara la alerta. Confirma que el anuncio coincide con lo que una persona vidente entendería al mirar la misma interfaz.
Al probar widgets personalizados, recorre el modelo de interacción con el teclado definido en la Guía de Prácticas de Autoría WAI-ARIA para ese tipo de widget. Si tu lista de pestañas no responde a las teclas de flecha, o tu diálogo no atrapa el foco, eso son fallos independientemente de lo correcto que parezca el marcado ARIA en una auditoría automatizada.
Conclusiones clave
- Prefiere siempre HTML semántico frente a ARIA. Los elementos nativos como
<button>,<nav>,<main>y<dialog>incorporan semántica de accesibilidad integrada que es más robusta y requiere mucho menos código que sus equivalentes con ARIA sobre un div. Recurre a ARIA solo cuando HTML nativo realmente se quede corto. - Los roles ARIA son una promesa, no un atajo. Aplicar
role='button'orole='dialog'a un elemento personalizado te compromete a implementar el modelo completo de interacción con el teclado para ese tipo de widget. Los roles sin un comportamiento correspondiente crean confusión e incumplimientos de WCAG. - Mantén los estados ARIA sincronizados con tu interfaz. Atributos dinámicos como
aria-expanded,aria-checked,aria-selectedy el contenido dearia-livedeben actualizarse en JavaScript a medida que la interfaz cambia. Un estado obsoleto es activamente perjudicial: comunica información incorrecta a la persona usuaria. - Usa regiones en vivo para actualizaciones de contenido dinámico. Cualquier contenido que se actualice sin recargar la página — notificaciones, mensajes de error, estados de carga, flujos de chat — necesita una región
aria-liveo un rol apropiado comoalertostatuspara que las personas usuarias de lectores de pantalla reciban automáticamente la misma información que ven las personas videntes. - Prueba con tecnologías de asistencia reales, no solo con herramientas automatizadas. Los escáneres automatizados detectan errores estructurales de ARIA, pero no pueden validar si tu implementación produce una experiencia coherente y utilizable. Las pruebas manuales con JAWS, NVDA y VoiceOver son la única forma de cerrar esa brecha.
