Внести вклад
Подробные руководства
Angular Aria

Grid

Обзор

Grid позволяет пользователям перемещаться по двумерным данным или интерактивным элементам с помощью стрелок, Home, End и Page Up/Down. Grids подходят для таблиц данных, календарей, электронных таблиц и layout-паттернов, группирующих связанные интерактивные элементы.

Использование

Grids хорошо подходят для данных или интерактивных элементов, организованных в строки и столбцы, где нужна клавиатурная навигация в нескольких направлениях.

Используйте grids, когда:

  • Строите интерактивные таблицы данных с редактируемыми или выбираемыми ячейками
  • Создаёте календари или date pickers
  • Реализуете интерфейсы в стиле spreadsheet
  • Группируете интерактивные элементы (кнопки, checkboxes), чтобы уменьшить число tab stops на странице
  • Строите интерфейсы, требующие двумерной клавиатурной навигации

Избегайте grids, когда:

  • Показываете простые read-only таблицы (вместо этого используйте семантический HTML <table>)
  • Показываете одноколоночные списки (вместо этого используйте Listbox)
  • Отображаете иерархические данные (вместо этого используйте Tree)
  • Строите формы без табличного layout (используйте стандартные form controls)

Возможности

  • Двумерная навигация — стрелки перемещают между ячейками во всех направлениях
  • Режимы фокуса — выбор между roving tabindex или activedescendant
  • Поддержка выбора — опциональный выбор ячеек в режимах single или multi-select
  • Поведение wrapping — настройка того, как навигация оборачивается на краях grid (continuous, loop или nowrap)
  • Выбор диапазона — выбор нескольких ячеек с modifier-клавишами или перетаскиванием
  • Состояния disabled — отключение всего grid или отдельных ячеек
  • Поддержка RTL — автоматическая навигация для языков справа налево

Примеры

Grid таблицы данных

Используйте grid для интерактивных таблиц, где пользователям нужно перемещаться между ячейками стрелками. Пример показывает базовую таблицу данных с клавиатурной навигацией.

Примените директиву ngGrid к элементу table, ngGridRow к каждой строке и ngGridCell к каждой ячейке.

Grid календаря

Календари — распространённый сценарий для grids. Пример показывает вид месяца, где пользователи перемещаются по датам стрелками.

Пользователи могут активировать дату, нажав Enter или Space, когда фокус на ячейке.

Layout grid

Используйте layout grid, чтобы группировать интерактивные элементы и уменьшить число tab stops. Пример показывает сетку pill-кнопок.

Вместо Tab по каждой кнопке пользователи перемещаются стрелками, и только одна кнопка получает tab-фокус.

Режимы выбора и фокуса

Включите выбор через [enableSelection]="true" и настройте взаимодействие фокуса и выбора.

<table
  ngGrid
  [enableSelection]="true"
  [selectionMode]="'explicit'"
  [multi]="true"
  [focusMode]="'roving'"
>
  <tr ngGridRow>
    <td ngGridCell>Cell 1</td>
    <td ngGridCell>Cell 2</td>
  </tr>
</table>

Режимы выбора:

  • follow: ячейка в фокусе выбирается автоматически
  • explicit: пользователи выбирают ячейки Space или кликом

Режимы фокуса:

  • roving: фокус перемещается к ячейкам через tabindex (лучше для простых grids)
  • activedescendant: фокус остаётся на контейнере grid, aria-activedescendant указывает активную ячейку (лучше для virtual scrolling)

Тестирование

Angular Aria предоставляет component harnesses для тестирования компонентов grid. Пример использования harnesses в тесте компонента:

import {ComponentFixture, TestBed} from '@angular/core/testing';
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {GridHarness} from '@angular/aria/grid/testing';
import {MyGridComponent} from './my-grid'; // Your component

describe('MyGridComponent', () => {
  let fixture: ComponentFixture<MyGridComponent>;
  let loader: HarnessLoader;

  beforeEach(async () => {
    TestBed.configureTestingModule({
      imports: [MyGridComponent],
    });

    fixture = TestBed.createComponent(MyGridComponent);
    await fixture.whenStable();
    loader = TestbedHarnessEnvironment.loader(fixture);
  });

  it('should read cell values and focus cells', async () => {
    const grid = await loader.getHarness(GridHarness);

    // Get all cells text in a 2D array organized by rows
    const cellTexts = await grid.getCellTextByIndex();
    expect(cellTexts).toEqual([
      ['Cell 1.1', 'Cell 1.2'],
      ['Cell 2.1', 'Cell 2.2'],
    ]);

    // Get a specific cell by text
    const cells = await grid.getCells({text: 'Cell 1.1'});
    expect(cells.length).toBe(1);
    const cell = cells[0];

    // Verify cell state
    expect(await cell.isSelected()).toBe(true);
    expect(await cell.isActive()).toBe(true);

    // Focus the cell
    await cell.focus();
    expect(await cell.isFocused()).toBe(true);
  });
});

API reference

Подробную API-документацию смотрите в следующих API reference: