Skip to main content
Niquelao

Some links here are partner links — we may earn a commission if you buy, at no extra cost to you. Details.

ARIA Role Button: Guía Completa y Práctica

El aria role button es un rol ARIA que hace que las tecnologías de asistencia anuncien un contenedor genérico como botón, pero no aporta comportamiento: hay que añadir tabindex="0", manejar Enter y Espacio, y reflejar el estado con aria-pressed o aria-disabled. La especificación WAI-ARIA 1.2 define este rol dentro de la categoría widget, y la primera regla de ARIA recomienda usar un <button> nativo siempre que sea posible.

El aria role button pertenece a la taxonomía de roles de WAI-ARIA, el estándar del W3C que describe semántica accesible para interfaces web. Cuando un elemento recibe role="button", el árbol de accesibilidad que construyen los lectores de pantalla (NVDA, JAWS, VoiceOver, Narrator) deja de exponerlo como un div o un span genérico y lo presenta como un control accionable. La diferencia es enorme para quien navega con lector de pantalla: sin el rol, el usuario oye “grupo” o simplemente texto; con el rol, oye “botón” y sabe que puede activarlo.

La confusión habitual es creer que role="button" convierte un div en un botón funcional. No lo hace. El rol solo cambia la semántica anunciada; el comportamiento —recibir foco, responder a teclado, disparar la acción— sigue siendo responsabilidad del desarrollador. Esta separación entre semántica y comportamiento es la raíz de la mayoría de errores que se cometen con este rol.

WAI-ARIA se publicó como recomendación del W3C y su versión 1.2 es la referencia vigente para roles, estados y propiedades. El rol button es uno de los roles de widget más antiguos y estables de la especificación, presente desde ARIA 1.0.

Cuándo usar role=“button” y cuándo no

La primera regla de ARIA, recogida en las prácticas de autoría de WAI-ARIA (WAI-ARIA Authoring Practices), es tajante: si existe un elemento HTML nativo con la semántica y el comportamiento que necesitas, úsalo. <button> ya trae el rol implícito, el foco por teclado, la activación con Enter y Espacio, y el estado deshabilitado. Reimplementar todo eso con el aria role role="button" es trabajo extra y fuente de bugs.

Existen, sin embargo, escenarios legítimos para el rol. El más común es cuando el marcado está condicionado por el framework o el CMS y no puedes introducir un <button> sin romper el layout o el JavaScript existente. Otro caso es el de componentes que deben comportarse como botón pero cuya estructura interna exige un contenedor específico, como ciertos widgets de terceros.

Related: con plan gratuito para empezar hoy mismo.

Un tercer escenario, más discutible, es el de elementos que ya tienen un rol nativo distinto y necesitan presentarse como botón. Aquí conviene preguntarse si el diseño no está forzando una semántica equivocada. Si algo parece un botón pero en realidad navega a otra página, lo correcto es un enlace <a>, no un botón.

SituaciónSolución recomendadaMotivo
Acción en formulario o interfaz<button> nativoRol, foco y teclado incluidos
Navegación a otra URL<a href>Semántica de enlace correcta
Contenedor no modificablerole="button" + teclado + estadosÚnico caso donde el rol aporta
Botón de alternancia (on/off)<button aria-pressed>Estado expuesto nativamente
Botón deshabilitado<button disabled>Estado y foco gestionados

Cómo implementar un botón con role=“button” correctamente

Un botón basado en role="button" necesita cubrir cuatro frentes: foco, teclado, estado y nombre accesible. Omitir cualquiera de ellos produce un control que “parece” accesible pero falla en pruebas reales.

El foco se habilita con tabindex="0", que inserta el elemento en el orden de tabulación natural. Nunca uses tabindex con valores positivos: alteran el orden de tabulación de toda la página y generan saltos impredecibles. El valor 0 es el correcto para elementos interactivos personalizados.

Worth a look: — Accesibilidad gestionada: automatización combinada con revisión humana.

El teclado requiere manejar dos teclas: Enter y Espacio. Un <button> nativo responde a ambas, pero un div con un aria role de botón no lo hace por sí solo. Hay que escuchar keydown y ejecutar la acción cuando la tecla es Enter o Space, evitando además el desplazamiento de página que provoca Espacio por defecto. Este detalle se pasa por alto con frecuencia y deja botones que solo funcionan con ratón.

El estado se comunica con atributos ARIA. Un botón de alternancia usa aria-pressed="true" o "false" para indicar si está activo. Un botón deshabilitado usa aria-disabled="true", que anuncia el estado pero no impide la interacción por sí solo: hay que bloquear la acción en el código. La diferencia entre aria-disabled y el atributo nativo disabled importa, porque el primero mantiene el elemento enfocable y el segundo lo saca del orden de tabulación.

El nombre accesible se construye con el texto visible del elemento o, si no hay texto, con aria-label o aria-labelledby. Un botón sin nombre accesible es un botón que el lector de pantalla anuncia como “botón” a secas, sin pista de qué hace.

<div
  role="button"
  tabindex="0"
  aria-pressed="false"
  id="btn-modo"
>
  Modo oscuro
</div>

<script>
  const btn = document.getElementById('btn-modo');
  function toggle() {
    const activo = btn.getAttribute('aria-pressed') === 'true';
    btn.setAttribute('aria-pressed', String(!activo));
  }
  btn.addEventListener('click', toggle);
  btn.addEventListener('keydown', (e) => {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      toggle();
    }
  });
</script>

El ejemplo anterior cubre foco, teclado, estado y nombre. Es el mínimo viable para que el control sea usable con lector de pantalla y teclado.

Errores frecuentes y cómo detectarlos

El error más extendido es aplicar role="button" sin tabindex, lo que produce un botón inalcanzable por teclado. Las herramientas automáticas lo detectan como “elemento con rol interactivo no enfocable”, una de las violaciones más reportadas en auditorías de accesibilidad.

El segundo error es no gestionar el teclado. Un div con un aria role de botón y tabindex pero sin manejadores de tecla recibe foco y no responde a Enter ni Espacio. El usuario de teclado queda atrapado: puede enfocar el botón pero no activarlo.

Related: — La que acredita tu experiencia en accesibilidad.

El tercer error es usar role="button" sobre un enlace. Esto rompe la semántica de navegación y confunde a los lectores de pantalla, que anuncian “botón” cuando el usuario espera un enlace. Si el elemento navega, debe ser un enlace.

El cuarto error es olvidar el estado en botones de alternancia. Un botón que cambia entre dos modos sin aria-pressed deja al usuario sin saber en qué estado se encuentra. El atributo es la única forma de comunicar ese estado de forma programática.

Para detectar estos problemas, las herramientas automáticas como axe, Lighthouse o WAVE señalan las violaciones de rol y foco, pero no validan el comportamiento de teclado ni la lógica de estado. Esa parte exige prueba manual: navegar con Tab, activar con Enter y Espacio, y escuchar la salida del lector de pantalla. La combinación de auditoría automática y prueba manual es la única forma fiable de validar un botón personalizado.

If you are shopping: — Superposición de IA que promete cumplimiento WCAG en 48 horas.

Cómo probar un botón con role=“button”

La prueba empieza por el teclado. Recorre la página con Tab y comprueba que el botón con el aria role button recibe foco visible. Pulsa Enter y Espacio por separado: ambos deben disparar la acción. Si Espacio desplaza la página en lugar de activar el botón, falta el preventDefault.

La segunda prueba es con lector de pantalla. NVDA en Windows, VoiceOver en macOS y Narrator en Windows son las referencias más usadas. Al enfocar el botón, el lector debe anunciar el rol (“botón”), el nombre accesible y el estado si lo tiene. Si anuncia “grupo” o no menciona el estado, algo falla.

La tercera prueba es de orden de foco. El botón debe aparecer en el orden lógico de tabulación, ni antes ni después de donde corresponde visualmente. Los tabindex positivos rompen este orden y son un indicador claro de mala implementación.

La cuarta prueba es de contraste y foco visible. El indicador de foco no debe eliminarse con outline: none sin sustituirlo por una alternativa visible. Un botón que recibe foco pero no lo muestra deja al usuario de teclado sin referencia de dónde está.

Alternativas modernas al rol button

El elemento <button> nativo sigue siendo la mejor opción en 2024 y en cualquier proyecto nuevo. Aporta rol, foco, teclado y estados sin código adicional, y los navegadores lo tratan de forma consistente.

Los custom elements o Web Components ofrecen otra vía. Un componente que extiende HTMLElement puede encapsular el comportamiento de botón y exponerlo con la semántica correcta, aunque requiere gestionar manualmente el foco y el teclado igual que con role="button". La ventaja es la reutilización; la desventaja, la misma responsabilidad de implementación.

Las ARIA in HTML (reglas que definen qué roles ARIA se permiten sobre cada elemento HTML) desaconsejan sobrescribir roles nativos. Aplicar el aria role role="button" a un <button> es redundante; aplicarlo a un <a> con href es contraproducente. La recomendación general es reservar el rol para contenedores sin semántica propia.

Key Takeaways

  • role="button" cambia solo la semántica anunciada; el foco, el teclado y el estado hay que implementarlos a mano.
  • La primera regla de ARIA recomienda usar <button> nativo siempre que el marcado lo permita.
  • Un botón con aria role button necesita tabindex="0", manejo de Enter y Espacio, nombre accesible y estado con aria-pressed o aria-disabled.
  • Las herramientas automáticas detectan la falta de foco, pero el comportamiento de teclado y estado exige prueba manual con lector de pantalla.
  • Nunca uses tabindex positivo ni apliques role="button" sobre enlaces que navegan.

Frequently Asked Questions

¿Cuál es la diferencia entre role=“button” y el elemento button?

El elemento <button> nativo incluye el rol implícito, el foco por teclado, la activación con Enter y Espacio y el estado deshabilitado sin código adicional. El atributo role="button" solo aporta la semántica anunciada; el resto del comportamiento debe programarse. Por eso la primera regla de ARIA recomienda el elemento nativo siempre que sea posible.

¿Necesito tabindex con role=“button”?

Sí. Un div o span con role="button" no es enfocable por defecto, así que sin tabindex="0" queda fuera del orden de tabulación y es inalcanzable con teclado. El valor correcto es 0; los valores positivos alteran el orden de tabulación de toda la página y deben evitarse.

¿Cómo hago que un div con role=“button” responda a Enter y Espacio?

Hay que escuchar el evento keydown y ejecutar la acción cuando la tecla es Enter o Space. En el caso de Espacio conviene llamar a preventDefault para evitar el desplazamiento de página. Sin estos manejadores, el botón recibe foco pero no se activa con teclado.

¿Cómo indico que un botón está activo o deshabilitado?

Para un botón de alternancia usa aria-pressed="true" o "false" según el estado. Para un botón deshabilitado usa aria-disabled="true", que anuncia el estado pero no bloquea la interacción por sí solo: hay que impedir la acción en el código. El atributo nativo disabled es preferible cuando se usa un <button>.

¿Es mala práctica usar role=“button” en un enlace?

Sí, cuando el enlace navega a otra URL. Sobrescribir el rol de un <a href> con role="button" rompe la semántica de navegación y confunde a los lectores de pantalla, que anuncian “botón” cuando el usuario espera un enlace. Si el elemento navega, debe conservar su rol de enlace.

¿Qué herramientas detectan errores con role=“button”?

Herramientas automáticas como axe, Lighthouse o WAVE señalan violaciones como la falta de foco en elementos con rol interactivo. Sin embargo, no validan el comportamiento de teclado ni la lógica de estado, así que la verificación fiable combina auditoría automática con prueba manual usando NVDA, VoiceOver o Narrator.

P.S. A few readers have asked which superposición de accesibilidad (overlay) we actually reach for — it's accessiBe; if you want the current details.

Frequently asked questions

¿Cuál es la diferencia entre role='button' y el elemento button?

El elemento <button> nativo incluye el rol implícito, el foco por teclado, la activación con Enter y Espacio y el estado deshabilitado sin código adicional. El atributo role='button' solo aporta la semántica anunciada; el resto del comportamiento debe programarse. Por eso la primera regla de ARIA recomienda el elemento nativo siempre que sea posible.

¿Necesito tabindex con role='button'?

Sí. Un div o span con role='button' no es enfocable por defecto, así que sin tabindex='0' queda fuera del orden de tabulación y es inalcanzable con teclado. El valor correcto es 0; los valores positivos alteran el orden de tabulación de toda la página y deben evitarse.

¿Cómo hago que un div con role='button' responda a Enter y Espacio?

Hay que escuchar el evento keydown y ejecutar la acción cuando la tecla es Enter o Space. En el caso de Espacio conviene llamar a preventDefault para evitar el desplazamiento de página. Sin estos manejadores, el botón recibe foco pero no se activa con teclado.

¿Cómo indico que un botón está activo o deshabilitado?

Para un botón de alternancia usa aria-pressed='true' o 'false' según el estado. Para un botón deshabilitado usa aria-disabled='true', que anuncia el estado pero no bloquea la interacción por sí solo: hay que impedir la acción en el código. El atributo nativo disabled es preferible cuando se usa un <button>.

¿Es mala práctica usar role='button' en un enlace?

Sí, cuando el enlace navega a otra URL. Sobrescribir el rol de un <a href> con role='button' rompe la semántica de navegación y confunde a los lectores de pantalla, que anuncian 'botón' cuando el usuario espera un enlace. Si el elemento navega, debe conservar su rol de enlace.

¿Qué herramientas detectan errores con role='button'?

Herramientas automáticas como axe, Lighthouse o WAVE señalan violaciones como la falta de foco en elementos con rol interactivo. Sin embargo, no validan el comportamiento de teclado ni la lógica de estado, así que la verificación fiable combina auditoría automática con prueba manual usando NVDA, VoiceOver o Narrator.


¿Cumplir WCAG sin tocar el código?

Superposición de IA que promete cumplimiento WCAG en 48 horas