diff --git a/packages/x-data-grid/src/hooks/features/export/serializers/csvSerializer.ts b/packages/x-data-grid/src/hooks/features/export/serializers/csvSerializer.ts index 0589aba5d346..385b5a41cf43 100644 --- a/packages/x-data-grid/src/hooks/features/export/serializers/csvSerializer.ts +++ b/packages/x-data-grid/src/hooks/features/export/serializers/csvSerializer.ts @@ -6,6 +6,9 @@ import type { GridApiCommunity } from '../../../../models/api/gridApiCommunity'; import { warnOnce } from '../../../../internals/utils/warning'; function sanitizeCellValue(value: unknown, csvOptions: CSVOptions): string { + if (value === null || value === undefined) { + return ''; + } const valueStr = typeof value === 'string' ? value : `${value}`; if (csvOptions.shouldAppendQuotes || csvOptions.escapeFormulas) { @@ -58,7 +61,7 @@ type CSVOptions = Required< >; type CSVRowOptions = { - sanitizeCellValue?: (value: any, csvOptions: CSVOptions) => any; + sanitizeCellValue?: (value: unknown, csvOptions: CSVOptions) => string; csvOptions: CSVOptions; }; class CSVRow { @@ -76,9 +79,7 @@ class CSVRow { if (!this.isEmpty) { this.rowString += this.options.csvOptions.delimiter; } - if (value === null || value === undefined) { - this.rowString += ''; - } else if (typeof this.options.sanitizeCellValue === 'function') { + if (typeof this.options.sanitizeCellValue === 'function') { this.rowString += this.options.sanitizeCellValue(value, this.options.csvOptions); } else { this.rowString += value; diff --git a/packages/x-data-grid/src/tests/export.DataGrid.test.tsx b/packages/x-data-grid/src/tests/export.DataGrid.test.tsx index 76852db95927..fd39af7dd1ad 100644 --- a/packages/x-data-grid/src/tests/export.DataGrid.test.tsx +++ b/packages/x-data-grid/src/tests/export.DataGrid.test.tsx @@ -117,6 +117,31 @@ describe(' - Export', () => { ].join('\r\n'), ); }); + + it('should export `undefined` and `null` values as blank', async () => { + render( +
+ +
, + ); + fireEvent.click(screen.getByRole('button', { name: 'Export' })); + clock.runToLast(); + expect(screen.queryByRole('menu')).not.to.equal(null); + fireEvent.click(screen.getByRole('menuitem', { name: 'Download as CSV' })); + expect(spyCreateObjectURL.callCount).to.equal(1); + const csv = await spyCreateObjectURL.lastCall.firstArg.text(); + + expect(csv).to.equal(['name', 'Name', '', '', '1234'].join('\r\n')); + }); }); describe('component: GridToolbarExport', () => {