diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4439faa251f..a441c63d1c4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
- Fixed logo icons with static SVG IDs causing accessibility errors when multiples of the same logo were present ([#5204](https://github.com/elastic/eui/pull/5204))
- Fixed several `EuiDataGrid` console errors that occur on column drag/drop reorder ([#5209](https://github.com/elastic/eui/pull/5209))
+- Fixed an accessibility issue where `EuiDataGrid` cells weren't owned by `role=row` elements ([#5213](https://github.com/elastic/eui/pull/5213))
**Reverts**
diff --git a/scripts/a11y-testing.js b/scripts/a11y-testing.js
index daaf22b469f..d66613d043d 100644
--- a/scripts/a11y-testing.js
+++ b/scripts/a11y-testing.js
@@ -13,15 +13,6 @@ const docsPages = async (root, page) => {
`${root}#/forms/color-selection`,
`${root}#/forms/date-picker`,
`${root}#/forms/super-date-picker`,
- `${root}#/tabular-content/data-grid`,
- `${root}#/tabular-content/data-grid-in-memory-settings`,
- `${root}#/tabular-content/data-grid-schemas-and-popovers`,
- `${root}#/tabular-content/data-grid-focus`,
- `${root}#/tabular-content/data-grid-styling-and-control`,
- `${root}#/tabular-content/data-grid-control-columns`,
- `${root}#/tabular-content/data-grid-footer-row`,
- `${root}#/tabular-content/data-grid-virtualization`,
- `${root}#/tabular-content/data-grid-row-heights-options`,
];
return [
diff --git a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap
index 27962a9b854..023f30801ad 100644
--- a/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap
+++ b/src/components/datagrid/__snapshots__/data_grid.test.tsx.snap
@@ -1039,6 +1039,11 @@ Array [
+
+
+
+
+
{
const requiredProps = {
+ gridId: 'grid',
isFullScreen: false,
headerIsInteractive: true,
rowCount: 1,
diff --git a/src/components/datagrid/body/data_grid_body.tsx b/src/components/datagrid/body/data_grid_body.tsx
index 6627c842c5e..ed9ff544744 100644
--- a/src/components/datagrid/body/data_grid_body.tsx
+++ b/src/components/datagrid/body/data_grid_body.tsx
@@ -10,6 +10,7 @@ import classNames from 'classnames';
import React, {
forwardRef,
FunctionComponent,
+ ReactElement,
useCallback,
useContext,
useEffect,
@@ -72,6 +73,7 @@ export const Cell: FunctionComponent
= ({
rowHeightsOptions,
getRowHeight,
rowHeightUtils,
+ gridId,
} = data;
const { headerRowHeight } = useContext(DataGridWrapperRowsContext);
@@ -119,12 +121,15 @@ export const Cell: FunctionComponent = ({
[`euiDataGridRowCell--${textTransform}`]: textTransform,
});
+ const cellId = `datagrid-${gridId}-cell-${rowIndex},${columnIndex}`;
+
if (isLeadingControlColumn) {
const leadingColumn = leadingControlColumns[columnIndex];
const { id, rowCellRender } = leadingColumn;
cellContent = (
= ({
cellContent = (
= ({
cellContent = (
= (
rowHeightUtils,
virtualizationOptions,
gridStyles,
+ gridId,
} = props;
const [headerRowRef, setHeaderRowRef] = useState(null);
@@ -673,6 +681,57 @@ export const EuiDataGridBody: FunctionComponent = (
finalWidth = window.innerWidth;
}
+ const [
+ {
+ renderedRowsStartIndex,
+ renderedRowsStopIndex,
+ renderedColumnsStartIndex,
+ renderedColumnsStopIndex,
+ },
+ setRenderedRowIndices,
+ ] = useState({
+ renderedRowsStartIndex: -1,
+ renderedRowsStopIndex: -1,
+ renderedColumnsStartIndex: -1,
+ renderedColumnsStopIndex: -1,
+ });
+
+ const onItemsRendered = useCallback<
+ Required['onItemsRendered']
+ >(
+ ({
+ overscanRowStartIndex,
+ overscanRowStopIndex,
+ overscanColumnStartIndex,
+ overscanColumnStopIndex,
+ }) => {
+ setRenderedRowIndices({
+ renderedRowsStartIndex: overscanRowStartIndex,
+ renderedRowsStopIndex: overscanRowStopIndex,
+ renderedColumnsStartIndex: overscanColumnStartIndex,
+ renderedColumnsStopIndex: overscanColumnStopIndex,
+ });
+ },
+ [setRenderedRowIndices]
+ );
+
+ const accessibilityRows: ReactElement[] = [];
+ for (let i = renderedRowsStartIndex; i <= renderedRowsStopIndex; i++) {
+ const rowId = `datagrid-${gridId}-row-${i}}`;
+ const ownedCells: string[] = [];
+ for (
+ let j = renderedColumnsStartIndex;
+ j <= renderedColumnsStopIndex;
+ j++
+ ) {
+ ownedCells.push(`datagrid-${gridId}-cell-${i},${j}`);
+ }
+
+ accessibilityRows.push(
+
+ );
+ }
+
return (
= (
mutationRef(el);
}}
>
+ {accessibilityRows}
{(IS_JEST_ENVIRONMENT || finalWidth > 0) && (
= (
interactiveCellId,
rowHeightsOptions,
rowHeightUtils,
+ gridId,
}}
rowCount={
IS_JEST_ENVIRONMENT || headerRowHeight > 0
diff --git a/src/components/datagrid/body/data_grid_cell.test.tsx b/src/components/datagrid/body/data_grid_cell.test.tsx
index 7b8e9592469..fbf0c7e10c8 100644
--- a/src/components/datagrid/body/data_grid_cell.test.tsx
+++ b/src/components/datagrid/body/data_grid_cell.test.tsx
@@ -15,6 +15,7 @@ import { EuiDataGridCell } from './data_grid_cell';
describe('EuiDataGridCell', () => {
const requiredProps = {
+ id: 'cell',
rowIndex: 0,
visibleRowIndex: 0,
colIndex: 0,
diff --git a/src/components/datagrid/body/data_grid_cell.tsx b/src/components/datagrid/body/data_grid_cell.tsx
index f5eca7ff69e..51c390d1a4d 100644
--- a/src/components/datagrid/body/data_grid_cell.tsx
+++ b/src/components/datagrid/body/data_grid_cell.tsx
@@ -396,6 +396,7 @@ export class EuiDataGridCell extends Component<
render() {
const {
+ id,
width,
isExpandable,
popoverContent: PopoverContent,
@@ -598,6 +599,7 @@ export class EuiDataGridCell extends Component<
}
ref={this.setCellRef}
{...cellProps}
+ id={id}
data-test-subj="dataGridRowCell"
onKeyDown={handleCellKeyDown}
onFocus={this.onFocus}
diff --git a/src/components/datagrid/data_grid.test.tsx b/src/components/datagrid/data_grid.test.tsx
index 18966b6046d..c3a19002221 100644
--- a/src/components/datagrid/data_grid.test.tsx
+++ b/src/components/datagrid/data_grid.test.tsx
@@ -535,6 +535,7 @@ describe('EuiDataGrid', () => {
Object {
"className": "euiDataGridRowCell euiDataGridRowCell--firstColumn customClass",
"data-test-subj": "dataGridRowCell",
+ "id": "datagrid-generated-id-cell-0,0",
"onBlur": [Function],
"onFocus": [Function],
"onKeyDown": [Function],
@@ -554,6 +555,7 @@ describe('EuiDataGrid', () => {
Object {
"className": "euiDataGridRowCell euiDataGridRowCell--lastColumn customClass",
"data-test-subj": "dataGridRowCell",
+ "id": "datagrid-generated-id-cell-0,1",
"onBlur": [Function],
"onFocus": [Function],
"onKeyDown": [Function],
@@ -573,6 +575,7 @@ describe('EuiDataGrid', () => {
Object {
"className": "euiDataGridRowCell euiDataGridRowCell--stripe euiDataGridRowCell--firstColumn customClass",
"data-test-subj": "dataGridRowCell",
+ "id": "datagrid-generated-id-cell-1,0",
"onBlur": [Function],
"onFocus": [Function],
"onKeyDown": [Function],
@@ -592,6 +595,7 @@ describe('EuiDataGrid', () => {
Object {
"className": "euiDataGridRowCell euiDataGridRowCell--stripe euiDataGridRowCell--lastColumn customClass",
"data-test-subj": "dataGridRowCell",
+ "id": "datagrid-generated-id-cell-1,1",
"onBlur": [Function],
"onFocus": [Function],
"onKeyDown": [Function],
diff --git a/src/components/datagrid/data_grid.tsx b/src/components/datagrid/data_grid.tsx
index b41984e7079..52da534f8cf 100644
--- a/src/components/datagrid/data_grid.tsx
+++ b/src/components/datagrid/data_grid.tsx
@@ -883,6 +883,7 @@ export const EuiDataGrid: FunctionComponent = (props) => {
rowHeightUtils={rowHeightUtils}
virtualizationOptions={virtualizationOptions || {}}
gridStyles={gridStyles}
+ gridId={gridId}
/>
diff --git a/src/components/datagrid/data_grid_types.ts b/src/components/datagrid/data_grid_types.ts
index 3ab5c00d620..137b09969cb 100644
--- a/src/components/datagrid/data_grid_types.ts
+++ b/src/components/datagrid/data_grid_types.ts
@@ -332,6 +332,7 @@ export interface EuiDataGridBodyProps {
rowHeightsOptions?: EuiDataGridRowHeightsOptions;
rowHeightUtils: RowHeightUtils;
gridStyles?: EuiDataGridStyle;
+ gridId: string;
}
export interface EuiDataGridCellValueElementProps {
/**
@@ -364,6 +365,10 @@ export interface EuiDataGridCellValueElementProps {
}
export interface EuiDataGridCellProps {
+ /**
+ * required when used outside of a role="row" element, so a row can own this cell
+ */
+ id?: string;
rowIndex: number;
visibleRowIndex: number;
colIndex: number;
@@ -396,7 +401,7 @@ export interface EuiDataGridCellState {
export type EuiDataGridCellValueProps = Omit<
EuiDataGridCellProps,
- 'width' | 'interactiveCellId' | 'popoverContent'
+ 'id' | 'width' | 'interactiveCellId' | 'popoverContent'
>;
export interface EuiDataGridControlColumn {
/**