Accessibility
@toolbox-web/grid follows the WAI-ARIA Grid Pattern to provide an accessible data grid experience. This page documents the ARIA attributes, keyboard interactions, and best practices.
ARIA Roles & Attributes
Section titled “ARIA Roles & Attributes”The grid applies the following ARIA roles and attributes automatically:
Grid Structure
Section titled “Grid Structure”| Element | Role | Attributes |
|---|---|---|
<tbw-grid> | grid | aria-rowcount, aria-colcount, aria-multiselectable |
| Header container | rowgroup | — |
| Header row | row | aria-rowindex="1" |
| Header cell | columnheader | aria-sort, aria-colindex |
| Body container | rowgroup | — |
| Data row | row | aria-rowindex, aria-selected, aria-expanded |
| Data cell | gridcell | aria-colindex, aria-selected, aria-readonly |
Dynamic Attributes
Section titled “Dynamic Attributes”| Attribute | Applied When | Values |
|---|---|---|
aria-sort | Column is sorted | ascending, descending, none |
aria-selected | Row or cell is selected | true, false |
aria-expanded | Row grouping/tree is active | true, false |
aria-multiselectable | Selection plugin allows multi-select | true |
aria-readonly | Cell is not editable | true |
aria-rowindex | Always (1-based) | Row position in full dataset |
aria-colindex | Always (1-based) | Column position |
Keyboard Navigation
Section titled “Keyboard Navigation”The grid implements full keyboard navigation following the WAI-ARIA grid pattern:
Basic Navigation
Section titled “Basic Navigation”| Key | Action |
|---|---|
| ↑ / ↓ | Move focus between rows |
| ← / → | Move focus between cells |
| Home | Move to first cell in row |
| End | Move to last cell in row |
| Ctrl + Home | Move to first cell in grid |
| Ctrl + End | Move to last cell in grid |
| PgUp | Scroll up one viewport |
| PgDn | Scroll down one viewport |
| ⇥ Tab | Move to next cell (wraps to next row) |
| ⇧ Shift + ⇥ Tab | Move to previous cell (wraps to previous row) |
Selection (with SelectionPlugin)
Section titled “Selection (with SelectionPlugin)”| Key | Action |
|---|---|
| Space | Toggle row selection |
| ⇧ Shift + ↑ ↓ ← → | Extend range selection |
| Ctrl + A | Select all rows/cells |
| Esc | Clear selection |
Editing (with EditingPlugin)
Section titled “Editing (with EditingPlugin)”| Key | Action |
|---|---|
| ↵ Enter | Start editing focused cell |
| F2 | Start editing (alternative) |
| Esc | Cancel editing |
| ⇥ Tab | Commit and move to next cell |
| ⇧ Shift + ⇥ Tab | Commit and move to previous cell |
| ↵ Enter (while editing) | Commit value |
Row Grouping / Tree
Section titled “Row Grouping / Tree”| Key | Action |
|---|---|
| Space | Toggle expand/collapse on group or tree node |
Context Menu (with ContextMenuPlugin)
Section titled “Context Menu (with ContextMenuPlugin)”| Key | Action |
|---|---|
| ⇧ Shift + F10 / ☰ Menu | Open context menu at focused cell |
| ↑ / ↓ | Navigate menu items |
| ↵ Enter / Space | Activate menu item |
| Esc | Close menu |
Focus Management
Section titled “Focus Management”Focus Indicators
Section titled “Focus Indicators”The grid uses visible focus indicators that meet WCAG 2.1 Level AA requirements:
tbw-grid { /* Customize focus ring */ --tbw-color-focus-ring: #2563eb;}The focus ring is 2px solid and uses outline (not border) so it doesn’t affect layout.
Focus Trapping
Section titled “Focus Trapping”When editing a cell, focus is trapped within the editor until the user commits (Enter/Tab) or cancels (Escape). Overlay editors (date pickers, dropdowns) use registerExternalFocusContainer() to extend the focus trap.
Roving Tabindex
Section titled “Roving Tabindex”The grid uses a roving tabindex pattern:
- Only the currently focused cell has
tabindex="0" - All other cells have
tabindex="-1" - This means Tab moves focus out of the grid, and Shift+Tab moves focus back to the last focused cell
Screen Reader Support
Section titled “Screen Reader Support”Labels and Descriptions
Section titled “Labels and Descriptions”Provide accessible labels for screen readers:
<tbw-grid aria-label="Employee directory">Or reference a visible heading:
<h2 id="grid-heading">Employees</h2><tbw-grid aria-labelledby="grid-heading">Live Regions
Section titled “Live Regions”The grid uses aria-live regions to announce dynamic changes to screen readers:
- Sort changes (“Sorted by Name, ascending”)
- Filter changes (“Filter applied on Name”, “All filters cleared”)
Column Headers
Section titled “Column Headers”Column headers include:
- Column name via text content
- Sort direction via
aria-sort - Filter state via
aria-description(“Filtered”)
High Contrast Mode
Section titled “High Contrast Mode”Using CSS Custom Properties
Section titled “Using CSS Custom Properties”The grid’s CSS variable system makes high contrast easy:
/* High contrast theme */tbw-grid.high-contrast { --tbw-color-bg: #000; --tbw-color-fg: #fff; --tbw-color-border: #fff; --tbw-color-header-bg: #1a1a1a; --tbw-color-row-hover: #333; --tbw-color-focus-ring: #ffff00; --tbw-color-accent: #00ffff;}Pre-built Contrast Theme
Section titled “Pre-built Contrast Theme”import '@toolbox-web/grid/themes/dg-theme-contrast.css';Windows High Contrast Mode
Section titled “Windows High Contrast Mode”The grid ships with a built-in @media (forced-colors: active) block that remaps all theming variables to Windows system colors (CanvasText, Canvas, Highlight, HighlightText). Focus rings and selected rows are also overridden to use Highlight. No extra configuration needed — it works automatically.
WCAG Compliance Checklist
Section titled “WCAG Compliance Checklist”| Criterion | Level | Status | Notes |
|---|---|---|---|
| 1.1.1 Non-text Content | A | ✅ | Icons have text alternatives |
| 1.3.1 Info and Relationships | A | ✅ | ARIA roles convey structure |
| 1.3.2 Meaningful Sequence | A | ✅ | DOM order matches visual order |
| 1.4.1 Use of Color | A | ✅ | Status not conveyed by color alone |
| 1.4.3 Contrast (Min) | AA | ✅ | Default theme meets 4.5:1 ratio |
| 1.4.11 Non-text Contrast | AA | ✅ | Focus indicators visible at 3:1 |
| 2.1.1 Keyboard | A | ✅ | All functions accessible via keyboard |
| 2.1.2 No Keyboard Trap | A | ✅ | Tab exits the grid; Escape exits editors |
| 2.4.3 Focus Order | A | ✅ | Logical focus order follows grid structure |
| 2.4.7 Focus Visible | AA | ✅ | Clear focus indicators |
| 4.1.2 Name, Role, Value | A | ✅ | ARIA attributes on all interactive elements |
What’s Automatic
Section titled “What’s Automatic”The grid handles most accessibility concerns out of the box:
- ARIA roles & attributes —
role="grid",role="row",role="gridcell",aria-rowcount,aria-colcount,aria-rowindex,aria-colindexare always set - Keyboard navigation — Arrow keys, Tab, Enter, Home/End, PgUp/PgDn all work by default (core feature, not a plugin)
- Column headers — Always rendered with
role="columnheader"; cannot be hidden - Column type inference — Types (
number,date,boolean) are auto-detected from the first data row - Grid label — Auto-derived from the shell title (
<tbw-grid-header title="...">orshell.header.titleconfig) - Windows High Contrast —
forced-colorsmedia query is built into core CSS - Live announcements — Sort and filter changes are announced via
aria-liveregions - Plugin ARIA — Selection, editing, filtering, tree, and grouping plugins manage their own ARIA attributes (
aria-selected,aria-readonly,aria-expanded,aria-multiselectable,aria-description)
Developer Responsibilities
Section titled “Developer Responsibilities”These require explicit action:
- Provide a grid label when not using a shell — Without
<tbw-grid-header title="...">, setgridAriaLabelin config or addaria-labelon the element - Test with screen readers — NVDA (Windows), VoiceOver (macOS), Orca (Linux)
- Don’t override keyboard handling — The grid follows WAI-ARIA patterns; custom key listeners may conflict
- Use the contrast theme for additional a11y — Import
dg-theme-contrast.cssfor higher contrast beyond the built-in forced-colors support