diff --git a/src-docs/src/views/datagrid/schema_columns/datagrid_columns_example.js b/src-docs/src/views/datagrid/schema_columns/datagrid_columns_example.js
index e553d1dccaf..cc5f073c1a9 100644
--- a/src-docs/src/views/datagrid/schema_columns/datagrid_columns_example.js
+++ b/src-docs/src/views/datagrid/schema_columns/datagrid_columns_example.js
@@ -298,6 +298,11 @@ schemaDetectors={[
EuiDataGridCellValueElementProps and returning a
React node.
+
+ When rendering footer cell values, we encourage turning off cell
+ expansion on cells without content with{' '}
+ setCellProps({'{ isExpandable: false }'}).
+
),
props: {
diff --git a/src-docs/src/views/datagrid/schema_columns/footer_row.js b/src-docs/src/views/datagrid/schema_columns/footer_row.js
index 4f5cdc4ebc8..4222e2fa4a5 100644
--- a/src-docs/src/views/datagrid/schema_columns/footer_row.js
+++ b/src-docs/src/views/datagrid/schema_columns/footer_row.js
@@ -66,17 +66,24 @@ const columns = [
];
const footerCellValues = {
- amount: `Total: $${raw_data.reduce(
- (acc, { amount }) => acc + Number(amount.split('$')[1]),
- 0
- )}`,
+ amount: `Total: ${raw_data
+ .reduce((acc, { amount }) => acc + Number(amount.split('$')[1]), 0)
+ .toLocaleString('en-US', { style: 'currency', currency: 'USD' })}`,
version: `Latest: ${
raw_data.map(({ version }) => version).sort()[raw_data.length - 1]
}`,
};
-const renderFooterCellValue = ({ columnId }) =>
- footerCellValues[columnId] || null;
+const RenderFooterCellValue = ({ columnId, setCellProps }) => {
+ const value = footerCellValues[columnId];
+
+ useEffect(() => {
+ // Turn off the cell expansion button if the footer cell is empty
+ if (!value) setCellProps({ isExpandable: false });
+ }, [value, setCellProps]);
+
+ return value || null;
+};
export default () => {
// Pagination
@@ -121,7 +128,7 @@ export default () => {
rowCount={raw_data.length}
renderCellValue={RenderCellValue}
renderFooterCellValue={
- showFooterRow ? renderFooterCellValue : undefined
+ showFooterRow ? RenderFooterCellValue : undefined
}
pagination={{
...pagination,
diff --git a/src/components/datagrid/body/data_grid_footer_row.spec.tsx b/src/components/datagrid/body/data_grid_footer_row.spec.tsx
new file mode 100644
index 00000000000..bae4600c7ae
--- /dev/null
+++ b/src/components/datagrid/body/data_grid_footer_row.spec.tsx
@@ -0,0 +1,94 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
+ * Side Public License, v 1.
+ */
+
+///
+
+import React, { useState, useEffect } from 'react';
+import { EuiDataGrid } from '../';
+
+describe('EuiDataGridFooterRow', () => {
+ const mockData = [10, 15, 20];
+
+ const RenderCellValue = ({ rowIndex, columnId }) =>
+ columnId === 'b' ? mockData[rowIndex] : null;
+
+ const RenderFooterCellValue = ({ columnId, setCellProps }) => {
+ const value = columnId === 'b' ? mockData.reduce((a, b) => a + b, 0) : null;
+
+ useEffect(() => {
+ if (!value) setCellProps({ isExpandable: false });
+ }, [value, setCellProps]);
+
+ return value;
+ };
+
+ // We need to set up a test component here for column ordering to work
+ const GridTest = () => {
+ const [visibleColumns, setVisibleColumns] = useState(['a', 'b']);
+
+ return (
+
+ );
+ };
+ GridTest.displayName = 'GridTest';
+
+ it('renders a footer of total values', () => {
+ cy.mount();
+
+ cy.get(
+ '[data-gridcell-column-index="1"][data-gridcell-row-index="3"]'
+ ).contains('45');
+ });
+
+ it('does not render an expansion button for the empty footer cell', () => {
+ cy.mount();
+
+ cy.get(
+ '[data-gridcell-column-index="0"][data-gridcell-row-index="3"]'
+ ).click();
+ cy.get('[data-test-subj="euiDataGridCellExpandButton"]').should(
+ 'not.exist'
+ );
+ });
+
+ // Regression test for #5720
+ it('does not bug focus when moving a column and then clicking its footer cell', () => {
+ cy.mount();
+
+ cy.get(
+ '[data-gridcell-column-index="1"][data-gridcell-row-index="-1"]'
+ ).click();
+ cy.contains('Move left').click();
+
+ cy.get('[data-gridcell-column-index="0"][data-gridcell-row-index="3"]')
+ .click()
+ .contains('45')
+ .click();
+
+ // Note that the wait/timeout and multiple focused assertions are required for
+ // for this specific bug which bounces focus rapidly between cells, as otherwise
+ // Cypress re-tries until it happens to be on the cell with correct attributes
+ cy.wait(50);
+ const checkFocusedCell = () => {
+ cy.wait(1);
+ cy.focused({ timeout: 0 })
+ .should('have.attr', 'data-gridcell-column-index', '0')
+ .should('not.have.attr', 'data-gridcell-column-index', '1');
+ };
+ checkFocusedCell();
+ checkFocusedCell();
+ checkFocusedCell();
+ });
+});
diff --git a/src/components/datagrid/body/data_grid_footer_row.test.tsx b/src/components/datagrid/body/data_grid_footer_row.test.tsx
index 33af4964473..eca2c81be9c 100644
--- a/src/components/datagrid/body/data_grid_footer_row.test.tsx
+++ b/src/components/datagrid/body/data_grid_footer_row.test.tsx
@@ -39,7 +39,7 @@ describe('EuiDataGridFooterRow', () => {
columnType="string"
interactiveCellId="someId"
isExpandable={true}
- key="someColumn-10"
+ key="0,10"
popoverContext={
Object {
"cellLocation": Object {
@@ -65,7 +65,7 @@ describe('EuiDataGridFooterRow', () => {
columnType={null}
interactiveCellId="someId"
isExpandable={true}
- key="someColumnWithoutSchema-10"
+ key="1,10"
popoverContext={
Object {
"cellLocation": Object {
diff --git a/src/components/datagrid/body/data_grid_footer_row.tsx b/src/components/datagrid/body/data_grid_footer_row.tsx
index fea8bdc8ea7..ca78dacc3cd 100644
--- a/src/components/datagrid/body/data_grid_footer_row.tsx
+++ b/src/components/datagrid/body/data_grid_footer_row.tsx
@@ -81,7 +81,7 @@ const EuiDataGridFooterRow = memo(
return (