Codea Bien Logo
Angular Aria: Componentes Headless Accesibles
Angular

Angular Aria: Componentes Headless Accesibles

Kevin Dávila

angularariaa11y

Hace poco estuve probando con Angular Aria y me quede impresionado con lo facil que ahora es construir componentes accesibles. Si alguna vez intentaste implementar un menu, un combobox o un arbol siguiendo las WAI-ARIA guidelines, sabes que es un dolor de cabeza absoluto.
La cantidad de atributos ARIA, navegacion por teclado, manejo de foco y soporte para lectores de pantalla es abrumadora.

Angular Aria resuelve esto de una vez por todas: son directivas headless que manejan toda la complejidad de accesibilidad por ti. Tu solo traes el HTML, el CSS y la logica de negocio.


Qué es Angular Aria exactamente?

Angular Aria es una coleccion de directivas headless que implementan los patrones WAI-ARIA comunes. Las directivas se encargan de:

  • Interacciones por teclado: navegacion con flechas, Enter, Escape, Space.

  • Atributos ARIA: aria-expanded, aria-selected, aria-pressed, etc.

  • Manejo de foco: movimiento logico entre elementos.

  • Soporte para lectores de pantalla: anuncios correctos de estado y contexto.

"Angular Aria is a collection of headless, accessible directives that implement common WAI-ARIA patterns. The directives handle keyboard interactions, ARIA attributes, focus management, and screen reader support" - Source: https://angular.dev/guide/aria/overview


Instalación

# terminal
npm install @angular/aria

Simple. Sin configuracion adicional.


Los 12 patrones disponibles

Angular Aria v22 incluye directivas para los patrones interactivos mas comunes:

Busqueda y seleccion

Componente

Descripcion

Autocomplete

Input de texto con sugerencias filtradas

Listbox

Lista de opciones single o multi-select

Select

Dropdown de seleccion unica

Multiselect

Dropdown de seleccion multiple

Combobox

Input coordinado con un popup

Navegacion y acciones

Componente

Descripcion

Menu

Dropdown menus con submenus anidados

Menubar

Barra de navegacion horizontal persistente

Toolbar

Grupo de controles con navegacion logica

Organizacion de contenido

Componente

Descripcion

Accordion

Paneles de contenido colapsables

Tabs

Interfaces con pestanas

Tree

Listas jerarquicas con expand/collapse

Grid

Datos bidimensionales con navegacion celda por celda


Ejemplo real: Toolbar con formato de texto

Veamos como se construye un toolbar de formato de texto (como el de un editor de texto). Sin Angular Aria, esto requeriria cientos de lineas de codigo para manejar teclado, ARIA y foco. Con Angular Aria:

// text-editor-toolbar.component.ts
import { Component } from '@angular/core';
import {
  Toolbar,
  ToolbarWidget,
  ToolbarWidgetGroup,
} from '@angular/aria/toolbar';

@Component({
  selector: 'app-text-editor-toolbar',
  imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
  templateUrl: './text-editor-toolbar.component.html',
  styleUrl: './text-editor-toolbar.component.css',
})
export class TextEditorToolbarComponent {}
<!-- text-editor-toolbar.component.html -->
<div [ngToolbar] aria-label="Text Formatting Tools">
  <!-- Grupo Undo/Redo -->
  <div class="group">
    <button
      [ngToolbarWidget]
      value="undo"
      type="button"
      aria-label="undo"
      class="material-symbols-outlined"
      translate="no"
    >
      undo
    </button>
    <button
      [ngToolbarWidget]
      value="redo"
      type="button"
      aria-label="redo"
      class="material-symbols-outlined"
      translate="no"
    >
      redo
    </button>
  </div>

  <div class="separator" role="separator"></div>

  <!-- Grupo Bold/Italic/Underline -->
  <div class="group">
    <button
      [ngToolbarWidget]
      value="bold"
      type="button"
      aria-label="bold"
      #bold="ngToolbarWidget"
      class="material-symbols-outlined"
      [aria-pressed]="bold.selected()"
      translate="no"
    >
      format_bold
    </button>
    <button
      [ngToolbarWidget]
      value="italic"
      type="button"
      aria-label="italic"
      #italic="ngToolbarWidget"
      class="material-symbols-outlined"
      [aria-pressed]="italic.selected()"
      translate="no"
    >
      format_italic
    </button>
    <button
      [ngToolbarWidget]
      value="underlined"
      type="button"
      aria-label="underlined"
      #underlined="ngToolbarWidget"
      class="material-symbols-outlined"
      [aria-pressed]="underlined.selected()"
      translate="no"
    >
      format_underlined
    </button>
  </div>

  <div class="separator" role="separator"></div>

  <!-- Grupo Alineacion (radio group) -->
  <div [ngToolbarWidgetGroup] role="radiogroup" class="group" aria-label="Text alignment options">
    <button
      [ngToolbarWidget]
      role="radio"
      type="button"
      value="align left"
      aria-label="align left"
      #leftAlign="ngToolbarWidget"
      class="material-symbols-outlined"
      [aria-checked]="leftAlign.selected()"
      translate="no"
    >
      format_align_left
    </button>
    <button
      [ngToolbarWidget]
      role="radio"
      type="button"
      value="align center"
      aria-label="align center"
      #centerAlign="ngToolbarWidget"
      class="material-symbols-outlined"
      [aria-checked]="centerAlign.selected()"
      translate="no"
    >
      format_align_center
    </button>
    <button
      [ngToolbarWidget]
      role="radio"
      type="button"
      value="align right"
      aria-label="align right"
      #rightAlign="ngToolbarWidget"
      class="material-symbols-outlined"
      [aria-checked]="rightAlign.selected()"
      translate="no"
    >
      format_align_right
    </button>
  </div>
</div>
/* text-editor-toolbar.component.css */
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');

:host {
  display: flex;
  justify-content: center;
}

[ngToolbar] {
  gap: 1.5rem;
  display: flex;
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  background-color: #f5f5f5;
}

.group {
  gap: 0.5rem;
  display: flex;
}

.separator {
  width: 1px;
  align-self: center;
  height: calc(100% - 1rem);
  background-color: #e0e0e0;
}

[ngToolbarWidget] {
  border: none;
  cursor: pointer;
  padding: 0.5rem;
  border-radius: 4px;
  font-size: 1.25rem;
  background-color: transparent;
  color: #333;
}

[ngToolbarWidget]:hover {
  background-color: rgba(0, 0, 0, 0.08);
}

[ngToolbarWidget]:active {
  background-color: rgba(0, 0, 0, 0.12);
}

[ngToolbarWidget]:focus {
  outline-offset: -1px;
  outline: 2px solid #1976d2;
}

[ngToolbarWidget][aria-pressed="true"],
[ngToolbarWidget][aria-checked="true"] {
  color: #1976d2;
  background-color: rgba(25, 118, 210, 0.1);
}

Que hace Angular Aria automaticamente por ti?

  1. Navegacion por teclado: las flechas mueven el foco entre widgets, Enter/Space activa.

  2. aria-pressed y aria-checked: se actualizan automaticamente basados en el estado del widget.

  3. Radio groups: ToolbarWidgetGroup maneja la logica de radio buttons (solo uno seleccionado).

  4. RTL support: la navegacion con flechas se invierte automaticamente en idiomas right-to-left.

  5. Focus trapping: el foco se mantiene dentro del toolbar mientras lo usas.


Cuando usar Angular Aria

Angular Aria brilla cuando necesitas:

  • Construir un design system: tu equipo mantiene una libreria de componentes con estandares visuales especificos que necesitan implementaciones accesibles.

  • Librerias de componentes enterprise: creas componentes reutilizables para multiples aplicaciones dentro de una organizacion.

  • Requisitos de marca personalizados: la interfaz debe coincidir con especificaciones de diseno precisas que las librerias pre-estilizadas no pueden acomodar facilmente.


Cuando NO usar Angular Aria

  • Componentes pre-estilizados: si necesitas componentes que se vean completos sin CSS custom, usa Angular Material.

  • Formularios simples: los controles nativos de HTML como <button> y <input type="radio"> ya proporcionan accesibilidad para casos basicos.

  • Prototipado rapido: cuando validas conceptos rapido, las librerias pre-estilizadas reducen el tiempo de desarrollo inicial.

"Angular Aria works well when you need accessible interactive components that are WCAG compliant with custom styling" - Source: https://angular.dev/guide/aria/overview


Angular Aria vs Angular CDK vs Angular Material

Criterio

Angular Aria

Angular CDK

Angular Material

Estilos incluidos

No

No

Si

Accesibilidad completa

Si

Parcial

Si

Customizacion visual

Total

Total

Limitada

Patrones ARIA

12 patrones

Behaviors genericos

Componentes completos

Curva de aprendizaje

Baja

Media

Baja

Mi recomendacion: si estas construyendo un design system custom, Angular Aria es el camino. Si necesitas algo rapido y bonito sin esfuerzo, Angular Material sigue siendo la opcion.


Accesibilidad: no es opcional

Segun la OMS, mas de 1000 millones de personas viven con alguna discapacidad. En muchos paises, la accesibilidad web no es solo buena practica, es ley (ADA en Estados Unidos, EAA en Europa).

Angular Aria hace que cumplir con WCAG sea mas facil que nunca. No necesitas ser un experto en accesibilidad: las directivas implementan los patrones correctos por ti.


Conclusión

Angular Aria representa un cambio fundamental en como construimos componentes interactivos accesibles. En lugar de confiar en que cada desarrollador implemente correctamente los patrones WAI-ARIA (spoiler: la mayoria no lo hace), Angular proporciona directivas probadas que hacen el trabajo pesado.

Si estas construyendo un sistema de componentes, dale una oportunidad a Angular Aria. Tus usuarios con discapacidades (y tu equipo de QA) te lo van a agradecer.

Para mas contenido sobre Angular y buenas practicas, visita Codea Bien.


Referencias adicionales:


SEO

Keywords: Angular Aria, componentes headless Angular, accesibilidad web Angular, WAI-ARIA Angular, design system Angular, componentes accesibles

Meta description: Aprende a construir componentes interactivos accesibles con Angular Aria. 12 patrones WAI-ARIA implementados como directivas headless. Toolbar, Menu, Combobox y mas.