Astryx Table Accessibility Features for Screen Readers: A Complete Implementation Guide
Astryx's Table component implements native HTML semantics, ARIA attributes, and keyboard navigation patterns including focusable scroll containers, sort announcements, row selection states, and hierarchical tree navigation.
Astryx is an open-source React component library developed by Meta (facebook/astryx). The Table component demonstrates enterprise-grade accessibility patterns that enable screen-reader users to navigate complex data grids effectively. This article examines the specific accessibility mechanisms implemented across the core table system and its plugin architecture.
Keyboard-Focusable Scroll Wrapper
Horizontal scrolling in data tables poses a significant accessibility challenge. Astryx solves this through the TableScrollWrapper component in packages/core/src/Table/Table.tsx.
The wrapper receives three critical attributes:
tabIndex={0}— makes the container keyboard-focusablerole="group"— identifies the scrollable region to assistive technologiesaria-label={t('@astryx.table.label')}— provides a translatable description
Lines 55-64 of Table.tsx implement this pattern:
<TableScrollWrapper
tabIndex={0}
role="group"
aria-label={t('@astryx.table.label')}
>
<table>{/* table content */}</table>
</TableScrollWrapper>
This allows keyboard-only users to focus the container with Tab, then navigate horizontally using arrow keys without requiring a physical scroll wheel.
Sortable Column Headers with ARIA Sort
When table sorting is enabled, Astryx communicates sort state through the useTableSortable plugin located in packages/core/src/Table/plugins/sortable/useTableSortable.tsx.
The implementation includes two ARIA mechanisms:
aria-sort on header cells — Applied to <th> elements with values "ascending", "descending", or omitted when unsorted. Lines 430-440 handle this assignment based on the current sort configuration.
Descriptive aria-label on sort buttons — Each clickable header receives a computed label announcing both the column name and current sort direction, enabling screen-reader users to understand the action before activation.
// When using the sortable plugin
const columns = [
{
key: 'name',
header: 'Name',
sortable: true, // Enables aria-sort handling automatically
},
];
Native Table Semantics for Screen Readers
Astryx preserves standard HTML table semantics through TableHeaderCell and TableCell components, ensuring assistive technologies can map relationships between headers and data cells.
TableHeaderCell (packages/core/src/Table/TableHeaderCell.tsx, lines 35-53)
The TableHeaderCellProps interface exposes:
scope— defines header association (colorrow)headers— references related header IDs for complex tablescolSpanandrowSpan— handles merged cells without breaking screen-reader navigation
TableCell (packages/core/src/Table/TableCell.tsx, lines 43-55)
TableCellProps mirrors these attributes for <td> elements, maintaining structural integrity across the table grid.
Row Selection State Announcement
The selection plugin in packages/core/src/Table/plugins/selection/useTableSelectionState.tsx manages selectable rows through lines 20-30.
Rows receive aria-selected="true" when actively selected, or the attribute is omitted for unselected rows. This pattern aligns with the WAI-ARIA grid and treegrid specifications, allowing screen readers to announce selection state during navigation.
import { useTableSelectionState } from '@astryxdesign/core/Table';
<Table
data={rows}
columns={columns}
plugins={{
selection: useTableSelectionState(),
}}
/>
Hierarchical Tree Navigation
For nested data structures, the tree plugin (packages/core/src/Table/plugins/tree/useTableTreeData.tsx, lines 200-215) adds hierarchical ARIA attributes:
aria-level— 1-based depth indicator for each rowaria-expanded— present on expandable nodes, announcing current expand/collapse state
These attributes enable screen-reader users to understand their position within nested data and anticipate expandable content.
Context Menu Accessibility
TableCell handles a subtle but important accessibility pattern in lines 14-22 of packages/core/src/Table/TableCell.tsx. When a custom right-click context menu is present, the component relocates padding to a full-size trigger element.
This ensures the entire cell area remains interactive for keyboard users, not just the visible text content. The menu remains accessible through standard keyboard activation without requiring mouse emulation.
Complete Implementation Example
The following example demonstrates multiple accessibility features working together:
import { Table } from '@astryxdesign/core';
import { useTranslator } from '@astryxdesign/core/i18n';
import { useTableSelectionState } from '@astryxdesign/core/Table/plugins/selection';
import { useTableTreeData } from '@astryxdesign/core/Table/plugins/tree';
function AccessibleTable() {
const t = useTranslator();
const columns = [
{
key: 'name',
header: t('@astryx.table.column.name'),
width: proportional(1),
sortable: true,
},
{
key: 'status',
header: t('@astryx.table.column.status'),
width: proportional(1),
},
];
return (
<Table
data={treeData}
columns={columns}
density="compact"
plugins={{
selection: useTableSelectionState(),
tree: useTableTreeData(),
}}
/>
);
}
This configuration activates: focusable scrolling, sort announcements, row selection states, and hierarchical navigation—all without additional accessibility configuration.
Summary
- Focusable scroll wrapper —
tabIndex,role="group", andaria-labelenable keyboard scrolling inTable.tsx - Sort state announcement —
aria-sortand descriptive labels inuseTableSortable.tsx - Native table semantics —
scope,headers,colSpan,rowSpaninTableHeaderCell.tsxandTableCell.tsx - Row selection —
aria-selectedattribute viauseTableSelectionState.tsx - Hierarchical data —
aria-levelandaria-expandedinuseTableTreeData.tsx - Context menu reachability — Full-cell activation area in
TableCell.tsx
Frequently Asked Questions
Does Astryx Table require manual ARIA configuration?
No. Accessibility attributes are applied automatically when using standard props and plugins. The sortable column property enables aria-sort, selection and tree plugins inject their respective ARIA attributes, and the scroll wrapper receives proper labeling through the translation system. Developers only need to provide translated strings via the useTranslator hook.
How does Astryx handle horizontal scrolling for keyboard users?
The TableScrollWrapper component in Table.tsx receives tabIndex={0} and role="group", making the scrollable region focusable. Once focused, users can scroll horizontally using arrow keys. The wrapper also includes an aria-label to describe the table's purpose to screen-reader users navigating by landmark.
What screen-reader announcements occur when sorting columns?
When a column header with sortable: true is activated, the sort button's aria-label announces both the column name and the resulting sort direction (e.g., "Name, sorted ascending"). The <th> element simultaneously receives aria-sort="ascending" or aria-sort="descending", which some screen readers may announce when navigating through the table structure.
Are hierarchical tree tables fully accessible?
Yes. The tree plugin provides aria-level for depth indication and aria-expanded for fold state on every expandable row. This allows screen-reader users to understand their position in nested data and control expansion without visual reference to indentation or icons.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →