Библиотека React Aria предоставляет мощные хуки для
создания доступных компонентов пользовательского интерфейса. Среди них
useTableHeaderRow и useTableRow предназначены
для работы с таблицами, обеспечивая правильную семантику, управление
фокусом и поддержку клавиатурной навигации.
useTableHeaderRow используется для создания строки
заголовка таблицы (<thead> /
<tr>), обеспечивая корректную разметку и доступность.
Этот хук автоматически добавляет необходимые ARIA-атрибуты, учитывая
структуру таблицы и сортируемость столбцов.
Синтаксис:
const { rowProps } = useTableHeaderRow({ node, state });
node — объект типа TableHeaderRowNode из
состояния таблицы (useTableState), описывающий заголовок
строки.state — объект состояния таблицы, управляемый хуком
useTableState.Возвращаемое значение:
rowProps — свойства, которые следует передать элементу
<tr>. Они включают правильные ARIA-атрибуты и
обработчики событий.Пример использования:
import { useTableHeaderRow } from "@react-aria/table";
import { useTableState } from "@react-stately/table";
function TableHeader({ columns }) {
let state = useTableState({ columns });
let headerRow = state.collection.headerRows[0];
let { rowProps } = useTableHeaderRow({ node: headerRow, state });
return (
<thead>
<tr {...rowProps}>
{headerRow.childNodes.map((column) => (
<th key={column.key}>{column.rendered}</th>
))}
</tr>
</thead>
);
}
Ключевые моменты:
row, columnheader.rowProps гарантирует совместимость с технологией чтения
с экрана и навигацией с клавиатуры.useTableRow применяется для обычной строки таблицы
(<tr>), обеспечивая правильное выделение, фокус и
интеграцию с useTableSelection для выбора строк.
Синтаксис:
const { rowProps } = useTableRow({ node, state });
node — объект типа TableRowNode,
описывающий текущую строку таблицы.state — объект состояния таблицы
(useTableState), который содержит информацию о выбранных
строках, фокусе и сортировке.Возвращаемое значение:
rowProps — свойства для элемента
<tr>, включая обработку фокуса и выделения.Пример использования:
import { useTableRow } from "@react-aria/table";
import { useTableState } from "@react-stately/table";
function TableBody({ rows }) {
let state = useTableState({ items: rows });
return (
<tbody>
{state.collection.body.map((row) => {
let { rowProps } = useTableRow({ node: row, state });
return (
<tr key={row.key} {...rowProps}>
{row.childNodes.map((cell) => (
<td key={cell.key}>{cell.rendered}</td>
))}
</tr>
);
})}
</tbody>
);
}
Особенности:
state.selectionManager.focusable,
tabIndex) для клавиатурной навигации.role="row", aria-selected,
aria-rowindex.Для полноценной таблицы рекомендуется использовать оба хука вместе с
useTableState:
useTableState.useTableHeaderRow.useTableRow для каждой строки.state.selectionManager.Пример полной таблицы:
import { useTableState } from "@react-stately/table";
import { useTableHeaderRow, useTableRow } from "@react-aria/table";
function Table({ columns, rows }) {
let state = useTableState({ columns, items: rows });
return (
<table>
<thead>
{state.collection.headerRows.map((headerRow) => {
let { rowProps } = useTableHeaderRow({ node: headerRow, state });
return (
<tr key={headerRow.key} {...rowProps}>
{headerRow.childNodes.map((column) => (
<th key={column.key}>{column.rendered}</th>
))}
</tr>
);
})}
</thead>
<tbody>
{state.collection.body.map((row) => {
let { rowProps } = useTableRow({ node: row, state });
return (
<tr key={row.key} {...rowProps}>
{row.childNodes.map((cell) => (
<td key={cell.key}>{cell.rendered}</td>
))}
</tr>
);
})}
</tbody>
</table>
);
}
Преимущества подхода:
column.sortable и
передавать обработчики через state.react-virtual), при этом useTableRow
корректно обновляет фокус при появлении новых строк.rowProps и thProps/tdProps
исключительно через деструктуризацию, чтобы не потерять встроенные
обработчики событий и ARIA-атрибуты.Этот подход обеспечивает полную совместимость с WAI-ARIA стандартами и делает таблицы в React максимально доступными и управляемыми с клавиатуры и экранных читалок.