Lattice Grid Buy a licence

demo D117

Screen reader

What the grid announces, and the ARIA it writes

aria-rowindex · aria-selected

Building…
Loading a live grid…

The configuration

import * as ng from '@angular/core';
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import createLatticeGrid from '@toclocoinc/lattice-grid/modules/angular';

const { LatticeGridComponent } = createLatticeGrid({ ng, createGrid });

// Roles, row and column indices, and sort state are all written, and
// aria-selected marks the selected rows for assistive technology.
const columns = [
  { field: 'service', title: 'Service', layout: { width: 150 } },
  { field: 'team', title: 'Team', filter: { type: 'set' } },
  { field: 'state', title: 'State' },
  { field: 'instances', title: 'Instances', type: 'number' },
  { field: 'uptime', title: 'Uptime', type: 'number', format: { style: 'percent', decimals: 3 } },
];

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [LatticeGridComponent],
  template: '<lattice-grid [config]="grid" style="display:block;height:540px"></lattice-grid>',
})
export class AppComponent implements AfterViewInit {
  @ViewChild(LatticeGridComponent) gridRef!: LatticeGridComponent;

  grid = {
    rowKey: 'id',
    selection: 'multiple',
    columns,
    rows: [/* service records */],
  };

  // Selected through the API so aria-selected is true on something: the attribute
  // assistive technology reads, which no gesture currently sets.
  ngAfterViewInit() {
    const grid = this.gridRef && this.gridRef.grid;
    if (!grid) return;
    const keys = [1, 2].map((i) => grid.rows.get(i)?.key).filter(Boolean);
    if (keys.length) grid.selection.set(keys);
  }
}

bootstrapApplication(AppComponent);

What a screen reader hears when it lands on a grid

A JavaScript data grid that virtualises its rows presents a problem no static table has: the DOM only contains the cells currently on screen, so a screen reader’s row and column counts have to come from attributes, not from counting children. Lattice Grid writes aria-rowindex and aria-colindex on every rendered cell against the full logical size of the data, not the rendered window, so a user hears “row 4,208 of 1,000,000” even though row 4,208 is the only one of those in the DOM at that moment. Selection state is exposed the same way: aria-selected tracks the grid’s own selection model on the row and, where relevant, the cell, so a checkbox column and a screen reader announcement never drift apart. A developer reaches for this when a procurement checklist names WCAG or Section 508, or when support tickets show a user navigating with NVDA, JAWS or VoiceOver rather than a mouse. The grid role structure follows the ARIA grid pattern, with aria-rowcount and aria-colcount set on the container so assistive technology can announce position without walking the whole dataset, and it holds regardless of column virtualisation, so a wide grid with two hundred columns still reports the same indices for the ones currently off-screen.

Does a virtualised JavaScript data grid work with a screen reader?

It can, provided the rows and columns still on screen carry position information about the full dataset, not just the rendered subset. Lattice Grid sets aria-rowindex, aria-colindex, aria-rowcount and aria-colcount from the logical grid size, and keeps aria-selected in step with its selection model, so announcements stay correct as the DOM recycles during scrolling.