# Angular Aria Angular Aria (`@angular/aria`) is a collection of headless, accessible directives that implement common WAI-ARIA patterns. These directives handle keyboard interactions, ARIA attributes, focus management, and screen reader support. **As an AI Agent, your role is to provide the HTML structure and CSS styling**, while the directives handle the complex accessibility logic. ## Styling Headless Components Because Angular Aria components are headless, they do not come with default styles. You **must** use CSS to style different states based on the ARIA attributes or structural classes the directives automatically apply. Common ARIA attributes to target in CSS: - `[aria-expanded="true"]` / `[aria-expanded="false"]` - `[aria-selected="true"]` - `[aria-disabled="true"]` - `[aria-current="page"]` (for navigation) --- **CRITICAL**: Before using this package, it must be installed via the package manager. Confirm that it has been installed in the project. Use `npm install @angular/aria` to install if necessary. ## 1. Accordion Organizes related content into expandable/collapsible sections. **Usage:** The Accordion is a layout component designed to organize content into logical groups that users can expand one at a time to reduce scrolling on content-heavy pages. Use it for FAQs, long forms, or progressive disclosure of information, but avoid it for primary navigation or scenarios where users must view multiple sections of content simultaneously. **Imports:** `import { AccordionContent, AccordionGroup, AccordionPanel, AccordionTrigger } from '@angular/aria/accordion';` **Directives:** `ngAccordionGroup`, `ngAccordionTrigger`, `ngAccordionPanel`, `ngAccordionContent` (for lazy loading). ```ts @Component({ selector: 'app-cmp', imports: [AccordionContent, AccordionGroup, AccordionPanel, AccordionTrigger], template: `...`, styles: [], }) export class App { protected readonly title = signal('angular-app'); } ``` ```html

Lazy loaded content here.

``` **Styling Strategy:** Target the `[aria-expanded]` attribute on the trigger to rotate icons, and style the panel visibility. ```css .accordion-header[aria-expanded='true'] .icon { transform: rotate(180deg); } /* The panel directive handles DOM removal, but you can style the transition */ .accordion-panel { padding: 1rem; border-top: 1px solid #ccc; } ``` --- ## 2. Listbox A foundational directive for displaying a list of options. Used for visible selection lists (not dropdowns). **Usage:** Visible selectable lists (single or multi-select). **Imports:** `import {Listbox, Option} from '@angular/aria/listbox';` **Directives:** `ngListbox`, `ngOption`. ```ts @Component({ selector: 'app-cmp', imports: [Listbox, Option], template: `...`, styles: [], }) export class App { protected readonly title = signal('angular-app'); } ``` ```html ``` **Styling Strategy:** Target `[aria-selected="true"]` for selected state and `:focus-visible` or `[data-active]` for the focused item (Angular Aria uses roving tabindex or activedescendant). ```css .option { padding: 8px; cursor: pointer; } .option[aria-selected='true'] { background: #e0f7fa; font-weight: bold; } /* Focus state managed by aria */ .option:focus-visible { outline: 2px solid blue; } ``` --- ## 3. Combobox, Select, and Multiselect These patterns combine the `ngCombobox` directive (applied directly to the trigger/combobox element) with a popup containing an `ngListbox` widget. - **Combobox (Autocomplete)**: Applied to an `` element. Ideal when typing filters the list. - **Select**: Applied to a focusable wrapper like a `
` or `
``` **Styling Strategy:** Target `[aria-pressed="true"]` (for toggle buttons) or `[aria-checked="true"]` (for radio groups) within the toolbar. ```css .toolbar { display: flex; gap: 5px; padding: 8px; background: #f5f5f5; } .tool-btn { padding: 5px 10px; border: 1px solid #ccc; } .tool-btn[aria-pressed='true'], .tool-btn[aria-checked='true'] { background: #ddd; } ``` --- ## 7. Tree Displays hierarchical data (file systems, nested nav). **Usage:** The Tree component is designed for navigating and displaying deeply nested, hierarchical data structures like file systems, organization charts, or complex site architectures. It should be used specifically for multi-level relationships where users need to expand or collapse branches, but it should be avoided for flat lists, data tables, or simple selection menus. **Imports:** `import {Tree, TreeItem, TreeItemGroup} from '@angular/aria/tree';` **Directives:** `ngTree`, `ngTreeItem`, `ngTreeItemGroup`. ```html ``` **Styling Strategy:** Target `[aria-expanded]` to show/hide children or rotate chevron icons. Use `padding-left` on nested groups to show hierarchy. ```css .tree, .tree-group { list-style: none; padding-left: 20px; } .tree-label::before { content: '▶ '; display: inline-block; transition: transform 0.2s; } li[aria-expanded='true'] > .tree-label::before { transform: rotate(90deg); } ``` ## 8. Grid A two-dimensional interactive collection of cells enabling navigation via arrow keys. **Usage:** Data tables, calendars, spreadsheets, and layout patterns for interactive elements. **Directives:** `ngGrid`, `ngGridRow`, `ngGridCell`, `ngGridCellWidget`. ```html
Name Status
Project A
``` **Styling Strategy:** Target `[aria-selected="true"]` for selected cells and `:focus-visible` for the active cell (roving tabindex) or `[aria-activedescendant]` on the container. ```css .grid-table { border-collapse: collapse; } [ngGridCell] { padding: 8px; border: 1px solid #ddd; } [ngGridCell][aria-selected='true'] { background: #e3f2fd; } /* Focus state managed by roving tabindex */ [ngGridCell]:focus-visible { outline: 2px solid #2196f3; outline-offset: -2px; } ``` ## 9. Testing with Component Harnesses Angular Aria provides standard Component Harnesses (based on `@angular/cdk/testing`) to make unit testing clean, robust, and decoupled from DOM structural details. **Imports:** ```ts import {HarnessLoader} from '@angular/cdk/testing'; import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed'; import {AccordionGroupHarness, AccordionHarness} from '@angular/aria/accordion/testing'; import {ListboxHarness, ListboxOptionHarness} from '@angular/aria/listbox/testing'; ``` ### Example: Testing an Accordion with Harnesses ```ts describe('MyAccordionComponent', () => { let fixture: ComponentFixture; let loader: HarnessLoader; beforeEach(async () => { fixture = TestBed.createComponent(MyAccordionComponent); await fixture.whenStable(); loader = TestbedHarnessEnvironment.loader(fixture); }); it('should expand accordion on toggle', async () => { // Get the harness by its trigger title const accordion = await loader.getHarness(AccordionHarness.with({title: 'Section 1'})); expect(await accordion.isExpanded()).toBeFalse(); // Expand the accordion await accordion.expand(); expect(await accordion.isExpanded()).toBeTrue(); }); }); ``` ## 10. Integration with Signal Forms Because Angular Aria directives leverage Angular's modern `model()` signals for managing interactive values, they integrate **out-of-the-box** with Angular's new Signal Forms (`@angular/forms/signals`). The `[formField]` directive automatically detects directives like `ngCombobox` or `ngListbox` as custom form controls because they expose a `value` model. **Imports:** ```ts import {form, schema, required} from '@angular/forms/signals'; import {Combobox, ComboboxPopup, ComboboxWidget} from '@angular/aria/combobox'; import {Listbox, Option} from '@angular/aria/listbox'; ``` ### Example 1: Autocomplete Combobox inside a Form Given a form model defined in your component: ```ts protected readonly citySignal = signal({name: '', city: ''}); protected readonly myForm = form(this.citySignal, schema(f => { required(f.city); })); ``` You bind it directly using `[formField]`: ```html
``` ### Example 2: Select Component inside a Form Apply `ngCombobox` directly to a focusable `div` trigger and bind to `[formField]`: ```html
{{ myForm.city.value() || 'Choose your city' }}
``` ### Example 3: Standalone Listbox (Multi-select) inside a Form You can bind a multi-selectable Listbox directly to a form array: ```html ``` ## General Rules for Agents 1. **Never use native HTML elements like `